2017-07-27 279 views
1

我有一個擴展AbstractTableModel類的TableModelBase。在那裏,我重寫了getValueAt方法,以便它返回行類的getter結果。Method.invoke不能使用包私有類

TableModelBase.java

@Log 
@AllArgsConstructor 
public abstract class TableModelBase<T> extends AbstractTableModel{ 
    @NonNull private final String[] columns; 
    @NonNull protected final transient List<T> rows; 

    //... 

    /** 
    * Default getValue method.<br> 
    * The row type fields must be in the same sequence that the columns.<br> 
    * Getter methods must follow the getter convention. 
    * @param rowIndex The row index. 
    * @param columnIndex The column index matches the field index of the row type. 
    * @return Object 
    */ 
    @Override 
    public Object getValueAt(int rowIndex, int columnIndex) { 
     final T row = rows.get(rowIndex); 
     if(row.getClass().getDeclaredFields().length != getColumnCount()) { 
      for (Field field : row.getClass().getDeclaredFields()) { 
       System.out.println(field.getName()); 
      } 
      log.severe("Fields number and table columns number are different in: " + row.getClass().getSimpleName()); 
      System.exit(1); 
     } 
     final Field field = row.getClass().getDeclaredFields()[columnIndex]; 

     String getter; 
     if(field.getType().equals(boolean.class)) { 
      getter = field.getName(); 
     } 
     else { 
      getter = "get" + Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1); 
     } 

     try { 
      Method method = row.getClass().getMethod(getter); 
      return method.invoke(row); 
     } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { 
      log.severe(e.getMessage()); 
      System.exit(1); 
      return null; 
     } 
    } 
} 

我在包TableModel的一個測試類TableModelTest。在這個包中還有類Data和DataModel。

Data.java

@Value 
class Data { 
    String text = "text"; 
    boolean isSuccessful = true; 
} 

DataModel.java

class DataModel extends TableModelBase<Data> { 
    DataModel() { 
     super(new String[]{"Text", "Is Successful"}, new ArrayList<>()); 
     rows.add(new Data()); 
    } 
} 

TableModelBaseTest

public class TableModelBaseTest { 
     @org.junit.Test 
     public void getValueAt() {  
      final DataModel dataModel = new DataModel(); 
      assertEquals("text",dataModel.getValueAt(0, 0)); 
      assertEquals(true, dataModel.getValueAt(0, 1)); 
     } 
} 

釷Ë測試給出一個IllegalAccessException:

類com.dsidesoftware.tablemodel.TableModelBase不能訪問類tablemodel.Data與修飾一 成員「公共」

的干將都是公開的,爲什麼我不能訪問它們?
奇怪的是,當我公開數據時,異常消失了。

有什麼想法發生了什麼?

謝謝。

+0

似乎數據具有「僅打包」可見性。這可能會導致拋出異常。你有什麼理由不公開數據嗎? – Shirkam

+0

@Shirkam我們可以想象一個包含數據類,模型和表的包。在這種情況下,只有桌子應該公開。我的問題更多的是理解發生的事情,而不是以不合時宜的方式解決問題。 –

+0

如果您使用任何地圖來存儲您的行屬性,這不會更簡單嗎?另外,我認爲你只是爲了簡潔而不寫數據獲取器。 – Shirkam

回答

0

我懷疑這與Data class中的字段是package-private有關。如果您想要規避此問題,請在獲得任何java.lang.reflect.AccessibleObject實例(即您的案例中的字段&方法)後立即致電setAccessible(true);。這將使他們對get()的呼叫忽略安全檢查。