2017-07-27 280 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()的呼叫忽略安全检查。