2013-11-04 123 views
1

我正在編寫一個應用程序,它使用java JDBC查詢並將數據插入到Oracle數據庫中。無法註冊JDBC驅動程序

我使用springframework API的SimpleDriverDataSource來實現標準的JDBC DataSource接口。

這裏是我的代碼

dataSource = new SimpleDriverDataSource(); 
dataSource.setDriverClass(Class.forName(credentials.getDriverClass())); 

我試圖保持代碼的獨立的DriverClass使用的一部分,我知道class.forName()返回類的字符串名稱的類的對象。

的問題是,我得到一個編譯錯誤說:

方法setDriverClass(Class<? extends Driver>)在類型SimpleDriverDataSource不適用於參數(Class<capture#1-of ?>

我真的不明白這些符號的含義,或者是什麼導致了錯誤?

+0

憑證是bean類的對象憑藉setter和getter來獲取用戶,傳遞等。並且getDriverClass()返回字符串「Oracle.jdbc.OracleDriver」 – ssayyed

回答

4

SimpleDriverDataSource#setDriverClass(Class)被實現爲

public void setDriverClass(Class<? extends Driver> driverClass) { 
    this.driver = BeanUtils.instantiateClass(driverClass); 
} 

所以它期待一個類型是Driver亞型的Class對象。

Class.forName(String)方法被實現爲

public static Class<?> forName(String className) 
      throws ClassNotFoundException { 
    return forName0(className, true, ClassLoader.getCallerClassLoader()); 
} 

換句話說,它返回一個Class<?>對象,即。任何類型的對象Class,不一定是Driver的子類型。因此,返回對象的聲明類型不是setDriverClass()方法的有效參數。

一種解決方案是自己實例化Driver類,並使用setDriver(Driver)方法,而不是

Class<?> clazz = Class.forName(credentials.getDriverClass()); 
Object driver = BeanUtils.instantiateClass(clazz); 
dataSource.setDriver((Driver) driver); 

注意的是,以上在運行時會拋出一個ClassCastException如果試圖將類實例不是Driver一個亞型。

另外,as suggested by BalusC您可以通過Class.forName()

SimpleDriverDataSource dataSource = new SimpleDriverDataSource(); 
dataSource.setDriverClass((Class<Driver>)Class.forName("com.mysql.jdbc.Driver")); 

投返回的值添加一些@SuppressWarnings,如果你不喜歡的IDE警告。

+1

您也可以在類「」傳遞給'setDriverClass()'(必要時用'@ SuppressWarnings')。 – BalusC

1

這是Java泛型的一個小技巧,值得了解。

當您處理的類型參數是 知道的是一致的,但在代碼中並不明確時,會出現問題。如果您正在處理不完全類型的集合,則這通常是 。考慮一個系統 ,它將不同的值從一個地方傳輸到另一個地方(可能是一個發送系統內不同類型消息的調度器)。

我們可能有一個接口,既可以提供和接受某些 消息類型:

public interface Connection<Type> 
{ 
    Type read(); 
    void write(Type value); 
} 

而且我們的調度可能看起來是這樣的:

class Scheduler 
{ 
    public void process(Collection<Connection<?>> cnxs) 
    { 
    for (Connection<?> cns: cnxs) { 
     cnx.write(cnx.read); 
    } 
    } 
} 

(請注意,是速記和我們在這裏使用它 ,因爲cnxs集合包含一個具有各種 不同類型參數的連接)。

不幸的是,不會編譯!給出的錯誤是Eclipse與Java 1.6是「 」類型的方法寫入(捕獲#2?)連接不適用於參數 (capture#3 of?)「。

不能編譯的原因是連接返回的值爲 的類型參數和值爲 的值的類型參數正在分別處理。每個被視爲 「捕獲??」這意味着「對象的一些子類」。然後編譯器 然後(可以理解)說:「我不能發送'Object'的子類X'到 方法,因爲我不知道它們是否是 是相同的子類」Object的子類Y「。

爲了使這項工作,我們需要明確引入通用類型參數 。不幸的是,下面的代碼或類似的東西, 不起作用(據我所知)。有沒有辦法來介紹一個代碼塊的中間 類型參數(我們真正想要的這裏是 的多態性更好的支持):

class Scheduler 
{ 
    public void process(Collection<Connection<?>> cnxs) 
    { 
    // syntax error! 
    for (<E> Connection<E> cns: cnxs) { 
     E value = cnx.read(); 
     cnx.write(value); 
    } 
    } 
} 

但我們可以做的是增加一個輔助方法推出新型 參數:

class Scheduler 
{ 
    public void process(Collection<Connection<?>> cnxs) 
    { 
    for (Connection<?> cnx: cnxs) { 
     helper(cnx); 
    } 
    } 
    private <E> void helper(Connection<E> cnx) 
    { 
    E value = cnx.read(); 
    cnx.write(value); 
    } 
} 

這就是我們想要的!代碼驗證,編譯和運行。總而言之:有時你可以「失去」一個明確的泛型 參數(通常是因爲你正在處理不同的 類型的集合)。您可以通過添加額外的輔助方法來重新引入該類型參數。

相關問題