2013-01-21 58 views
0

我需要得到一個Field(或一個字段列表),而不知道它的名字。Java:不知道名稱的訪問字段。 (「保存參考」)

即:自定義的EntityManager我希望能夠做到的方法調用是這樣的:

cem.getEntities(MyEntity.class, ParamMap)其中ParamMap應該是類型Map<Field, Object>的。

可以在瞬間做的是這樣的:

Map<Field, Object> params = new HashMap<Field, Object>(); 
params.put(MyEntity.class.getDeclaredField("someFieldName"), 20); 
List<MyEntity> entitysWithSomeFieldNameEquals20 = cem.getEntities(MyEntity.class, params); 

我試着避免querys的使用,因爲它應該擺在首位的工作「一般」,而且是獨立的來自Strings。 (他們很容易出錯)。因此,實體管理器使用反射來確定表格和列名稱,他需要使用。

不過,我仍然需要使用

MyEntity.class.getDeclaredField("someFieldName") 

這將簡單的移動容易出錯的字符串「走出去」的實體管理器的...

我正在努力實現將是這樣的:

MyEntity.class.getDeclaredField(MyEntity.class.fields.someFieldName.toString()) 

所以,無論什麼實際的場而得名,它可以在保存方式和重構引用將重構所有的現場訪問調用了。

我不確定這是否可能。我可以爲所有實體使用(封裝)枚舉,但我希望,這是更通用的方法來實現這一點。


編輯:

一個很好的解決方案似乎是常量的使用:

public class MyEntity{ 
    private static string SOME_FIELD = "some_field_name_in_database"; 

    @Column(name = SOME_FIELD); 
    private String someField; 

} 

... 
Map<String, Object> params = new HashMap<String, Object>(); 
params.put(MyEntity.SOME_FIELD, matchValue); 
List<MyEntity> result = eem.getEntities(MyEntity.class, params); 

這至少減少了串正好一個位置,它可以維持到使用並在不影響其他文件的情況下更改但是我仍然在尋找無常數的解決方案,所以contants 不需要與可用字段 :-)

+1

你想游泳但沒有變溼?使用字符串鍵的屬性集合有什麼問題?只要你讓它們成爲一個枚舉或類似的東西,它們就不再是「通用的」了。所以我認爲你的要求相互矛盾。 – Fildor

+0

但你確實知道該字段的名稱(這裏是「someFieldName」)?否則,你想如何用不知道字段名稱的值填充ParamMap?我想這裏的問題是你不想使用字符串? – proskor

+0

是的,當然我知道字段名稱。但我不想將它們(硬編碼)放入字符串中。所以問題是,如果我可以以某種方式引用它們,比如使用枚舉,而不爲每個實體(需要維護)創建一個枚舉。對每個實體使用嵌入式枚舉不起作用,因爲JPA不允許從枚舉中獲取列名(column.name需要是一個常量表達式)...不要誤解我的意思:更改實體總是會導致要做的工作。但是你不能找到某個字符串的每一個用法,比如你可以引用enums/Constants的用法。 – dognose

回答

0

好的同步,這只是一個想法,這是不容易實現,但它可以工作。

假設myEntity所看起來像這樣:

public class MyEntity { 
    private String foo; 
    private String bar; 

    public String getFoo() { return this.foo; } 
    public void setFoo(String foo) { this.foo = foo; } 

    public String getBar() { return this.bar; } 
    public void setBar(String bar) { this.bar = bar; } 

}

並且有一個接口:

public interface Pattern { 
    public Class<?> getEntityClass(); 
    public Map<Field, Object> getFields(); 
} 

並有一個方法,它採用一個類,並且產生一個圖形對象,這是給定類別的一個實例:

public class PatternFactory { 
    public <T> T createPattern(Class<T> klass) { 
    // magic happens here 
    } 
} 

對發出的實例的要求是它應該實現Pattern接口,這樣方法getFields只返回明確設置的字段。 GetEntityClass應該返回實體類。然後自定義實體管理器可以實現這樣的:

public class EntityManager { 
    public <T> Collection<T> getEntities(T pattern) { 
    if (!(pattern instanceof Pattern)) 
     throw new IllegalArgumentException(); 

    Class<?> klass = ((Pattern) pattern).getEntityClass(); 
    Map<Field, Object> fields = ((Pattern) pattern).getFields(); 
    // fetch objects here 
    } 
} 

然後,你可以使用這樣的:

PatternFactory pf = // obtain somehow 
EntityManager em = // obtain somehow 
MyEntity pattern = pf.createPattern(MyEntity.class); 
pattern.setFoo("XYZ"); 
pattern.setBar(null); 
Collection<MyEntity> result = em.getEntities(pattern); 

在這種情況下pattern.getFields會返回地圖的兩個項目。

當然,這裏的難點在於createPattern方法的實現,在這個方法中,您將不得不在運行時發出字節碼。但是,這是可能的,可以完成的。

相關問題