2015-04-08 52 views
0

我有一個項目,它基於一個可能會更改的XML模式。模式使用JAXB轉換爲Java。模式的幾個部分保證保持不變;特別是用戶必須填寫的表單的基本元素。一種在運行時查找另一個對象(包含列表)的所有子對象的方法

我想根據這個(被修改的)JAXB生成的代碼生成一個表單。問題在於,因爲我的代碼是不變的,但架構可以隨時更改,所以我不能在任何JAXB代碼中硬編碼,除了基本元素。

因此,我必須遞歸地找到基礎對象下的所有元素。這並不是太麻煩,有一點反射魔力(找到所有對象的'getter'方法的返回類型,重複)。真正的問題是當我遇到一個列表。因爲列表在運行時會丟失它們的類型,所以我無法確定列表包含的內容,並且無法進一步遞歸。

有沒有人有解決這個問題的出色解決方案?我已經研究了大多數其他方式來在運行時保留列表類型,但沒有任何工作。我很清楚,這可能是不可能的,但我想在放棄之前探索我的所有選擇。如果還有其他方法可以做到這一點,我願意嘗試。

我當前的代碼:

public static void getObjectDescendants(Object obj, int indent) throws Exception { 
    // Handle list of objects. 
    if (obj instanceof List) { 
     for(int i=0;i<indent;++i){System.out.print(" ");} 
     System.out.println("List"); 
     Class<?> clazz = getListType((List<?>) obj); // Get type of object within list 

     // Create new object of that type from constructor. (temp solution) 
     Object object = clazz.getConstructor().newInstance(); 

     getObjectDescendants(object, indent+1); 
     return; 
    } 

    // Handle regular object. 
    for (MethodDescriptor pd : Introspector.getBeanInfo(obj.getClass()).getMethodDescriptors()) { 
     // For each method this object has... 
     Method method = pd.getMethod(); 

     // If it does not return a complex object, or a list, we don't care about it. 
     if (!method.getReturnType().toString().contains("JAXB.generated.object") 
       && !method.getReturnType().toString().contains("java.util.List")) { 
      continue; 
     } 

     // Print out indent, and name of method. 
     for(int i=0;i<indent;++i){System.out.print(" ");} 
     System.out.println(method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()"); 

     Object object; 
     try { 
      if (method.getReturnType().equals(List.class)) { 
       object = method.invoke(obj); 
      } else { 
       Constructor<?> constructor = method.getReturnType().getConstructor(String.class); 
       object = constructor.newInstance(); 
      } 
     } catch (Exception e) { 
      continue; // Couldn't seem to handle this one. 
     } 

     getObjectDescendants(object, indent+1); 
    } 
} 

private static Class<?> getListType(final List<?> list) { 
    // Find out what object type is in the list, and return it. 
    Class<?> clazz = list.get(0).getClass(); // Doesn't work, since list is always empty. 
    return clazz; 
} 

回答

1

而是與反射進入JAXB類的,你可以使用JAXB模式。當您從類或包創建JAXB上下文時,它會創建這些類及其屬性的基礎模型。在運行時 - 基於註釋。在編譯期間(XJC) - 基於XML模式。

這是針對具體實現的,所以我會帶JAXB RI,因爲我知道它比MOXy好。

  • 當您使用JAXB RI創建JAXBContext時,您會在末尾獲得JAXBContextImpl的實例。
  • 這有一個方法getTypeInfoSet()返回RuntimeTypeInfoSet的實例。
  • 這個RuntimeTypeInfoSet是JAXB類的全部完整模型,屬性 - 你需要編組和解組。
  • 對於複雜類型你必須RuntimeClassInfo情況下,其具有的屬性(RuntimePropertyInfo

您可以分析這些結構的建立在運行時你的UI。這比挖掘反思容易得多。基本上這個Runtime...的東西做了所有必要的反映,所以你不必這樣做。順便說一句,我個人不會在這裏重新發明輪子,並且可以使用現有的模型驅動的UI生成方法之一,例如Metawidget。你必須將框架連接到JAXB模型,但它似乎比從頭開始整個事情更容易。大約7-8年前,我已經實現了基於JAXB的基於XML Schema驅動的UI生成,這真是一次冒險。有很多警告。

相關問題