2016-07-21 35 views
4

我們正在構建一個工具(僅供內部使用),它只有在從我們的源代碼中刪除了javax.persistence.GeneratedValue註釋(我們在工具中設置Id,並且由於GeneratedValue註釋而被拒絕)時纔會生效。但對於正常的操作,我們需要這個註釋。如何在運行時刪除Java註釋(可能使用反射)?

如何在運行時刪除Java註釋(可能使用反射)?

這是我的課:

@Entity 
public class PersistentClass{ 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    // ... Other data 
} 

這是我想什麼,能夠將其更改爲在運行時:

@Entity 
public class PersistentClass{ 
    @Id 
    private long id; 

    // ... Other data 
} 

這是可能做到這一點的類本身:

// for some reason this for-loop is required or an Exception is thrown 
for (Annotation annotation : PersistentClass.class.getAnnotations()) { 
    System.out.println("Annotation: " + annotation); 
} 

Field field = Class.class.getDeclaredField("annotations"); 
field.setAccessible(true); 
Map<Class<? extends Annotation>, Annotation> annotations = (Map<Class<? extends Annotation>, Annotation>) field.get(PersistentClass.class); 
System.out.println("Annotations size: " + annotations.size()); 
annotations.remove(Entity.class); 
System.out.println("Annotations size: " + annotations.size()); 

如果您可以從字段中獲取註釋映射,那麼將應用相同的解決方案。

+5

更好問題在於如何讓這個工具能夠在註釋中出現,我想。 – SpaceTrucker

回答

-1

創建一個新的庫,其中實體源被複制並過濾以刪除註釋。這既不硬也不潔。

你也可以試試ClassLoader和字節碼操作。但是類加載是一個cesspit。

+0

雖然這不是一個長期的解決方案。它需要不斷維護兩個實體類的副本。 – HeavyE

+0

是的,它必須被添加到構建基礎結構中,就像maven中的項目依賴項。 –

1

您不能在運行時刪除註釋。反射只檢查代碼。

你可以做的是:

  1. 保持包含註釋的源的主版本 你原來的目的(這是在代碼的版本檢查)
  2. 製造副本作爲構建步驟的一部分,刪除了註釋的源代碼。您在需要時使用此副本;你不檢查它。

你可以刪除註釋使用字符串黑客工具,如Perl或SED。這些可能會非常可靠,但是用於執行此操作的實際命令可能相當隱蔽。

如果您可以以原則方式修改源代碼版本,則可以使用program transformation system (PTS)這些工具可將源解析爲編譯器數據結構,讓您指定(結構化)「變換」以應用於代碼,以可靠的方式將變換應用於結構,然後爲更改後的程序重新生成(有效)源代碼。

良好的PTS會讓你在表面語法來指定這樣的變換:

if you see *this* pattern, replace it by *that* pattern 

其中,所述圖案基本上與目標語言代碼(例如,Java)來的片段。

(我碰巧構建了這些PTS中的一個)。具體的規則(我的PTS)可能看起來像:

rule remove_Generated_value(a: annotations, e: expression): 
      annotations -> annotations = 
     " \a @GeneratedValue(strategy = \e) " -> " \a "; 

這上面說,「如果你找到一個列表含GeneratedValue註釋與任何價值的‘戰略’屬性的註釋」,取代( (這是因爲註釋列表是可交換的,所以我們總是可以像一個有趣的成員是列表的最後一個成員一樣行事。](「標記是元引語 ;它們將規則語言的語法與模式中Java的語法區分開來)。