2012-02-12 11 views
7

La mia domanda riguarda la scrittura di plugin JAXB, in particolare codemodel JAXB.Qual è il ruolo di ClassOutline/JClass/CClass in CodeModel?

Qual è il ruolo di ClassOutline (ed è companions) e JClass (e companions) e CClass (e companions)? Quando si guarda l'elenco delle classi nei pacchetti corrispondenti non è chiaro cosa sia il pollo e cosa sia l'uovo.

La mia interpretazione è che CClass (CPropertyInfo, CEnumConstant, ...) sono creati da XJC alla prima bozza di parsing di XSD. Quindi accade un po 'di magia e questo modello viene trasformato in JClass (JFieldVar, JEnumConstant, ...) e durante questa trasformazione vengono applicate le personalizzazioni. Successivamente vengono richiamati i plugin. ClassOutline viene utilizzato come ponte tra questi due modelli. Complessivamente sembra molto complicato.

Con questi modelli paralleli credo che le stesse informazioni possano essere derivate in diversi modi. Ad esempio, il tipo di campo di classe:

  • JClass#fields() → → JFieldVar#typeJType
  • CClassInfo#getProperties() → → CPropertyInfo#baseTypeJType

Sto cercando una spiegazione dettagliata del ciclo di vita dei modelli di cui sopra. Grazie.

risposta

17

Oh, oh, qualcuno è interessato agli interni XJC. Potrei essere di aiuto dato che probabilmente ho sviluppato più plugin JAXB di chiunque altro (vedi JAXB2 Basics per esempio)

Ok, iniziamo. Nel XJC il compilatore schema non seguendo approssimativamente

  • analizza lo schema
  • crea il modello dello schema (CClass, CPropertyInfo ecc)
  • crea il contorno (ClassOutline, FieldOutline ecc)
  • Renders il codice del modello (JClass, JDefinedClass, JMethod ecc)
  • Scrive il codice fisico (file ex.Java sul disco)

Iniziamo con gli ultimi due.

I file Java non necessitano di una spiegazione, spero.

Il modello di codice è anche una cosa relativamente facile. È un'API che può essere utilizzata per costruire codice Java a livello di codice. Potresti semplicemente usare la concatinazione delle stringhe, ma è molto più soggetta a errori. Con CodeModel hai quasi la certezza di ottenere almeno il codice Java corretto grammaticamente. Quindi spero che anche questa parte sia chiara. (A proposito, mi piace molto CodeModel. Ho recentemente scritto JavaScript Code Model sulla base di idee dal CodeModel.)

Osserviamo ora il "modello" e il "contorno". Il modello è il risultato dell'analisi dello schema in entrata. Modella i costrutti dello schema entrante, principalmente in termini di "classi" che corrispondono a tipi complessi e "proprietà" che corrispondono a elementi, attributi e valori (es.quando hai un tipo complesso con un contenuto semplice).

Il modello deve essere interpretato come un costrutto di modellazione logica vicino a XML e schema. In quanto tale, descrive solo i tipi e le proprietà che hanno. È sicuramente molto più complesso di come lo sto descrivendo, ci sono tutti i tipi di eccezioni e caveat - a partire dai tipi di wilcard (xsd: any), gruppi di sostituzione, enumerazioni, tipi built-in e così via.

Abbastanza interessante, un fratello di è RuntimeTypeInfoSetImpl utilizzato da JAXB nel runtime. Quindi è anche un tipo di modello, che tuttavia non viene analizzato dallo schema XML ma piuttosto dalle annotazioni JAXB nelle classi. Il concetto è lo stesso. Entrambi i modelli e RuntimeTypeInfoSetImpl implementano l'interfaccia TypeInfoSet che è un super-costrutto. Controlla interfacce come ClassInfo e PropertyInfo - hanno implementazione sia per la fase di compilazione (CClassInfo e CPropertyInfo in XJC) che di esecuzione (RuntimeClassInfoImpl ecc. Per JAXB RI).

Ok, quindi, quando XJC ha analizzato e analizzato lo schema, hai il Model. Questo non può ancora produrre il codice. Esistono, infatti, diverse strategie per produrre il codice. È possibile generare solo classi annotate o generare un'interfaccia/implementazione di coppie di classi come in JAXB 1. L'intera generazione di codice non è in realtà il compito del modello. Inoltre, esiste una serie di aspetti rilevanti per la natura fisica del codice Java, ma non rilevanti per il modello. Ad esempio, devi raggruppare le classi in pacchetti. Questo è guidato dal sistema di impacchettamento di Java, non dalle proprietà del modello stesso.

E qui entrano in gioco i contorni. È possibile visualizzare i contorni come passaggio tra il modello dello schema e il modello di codice. È possibile visualizzare i contorni come fabbriche per gli elementi del modello di codice responsabili dell'organizzazione del codice e della generazione di JDefinedClass es da CClassInfo s.

Quindi hai ragione, è davvero molto complicato. Non sono un dipendente Sun/Oracle, non l'ho progettato (conosco la persona che lo ha fatto, però e lo rispetto molto). Posso immaginare un paio di motivi per alcune decisioni di progettazione, per esempio: modelli

  • utilizzare la stessa interfaccia per la fase di compilazione e di run-time
  • Consentire diverse strategie di generazione di codice
  • accettano plugin per manipolare il modello creato

Sono d'accordo che questo progetto è molto complicato, ma ha le sue ragioni. Una prova è che è stato effettivamente possibile creare un generatore di mapping per i mapping XML-to-JavaScript, in pratica sugli stessi modelli. Ho appena dovuto sostituire la generazione del codice lasciando intatta l'analisi dello schema. (Vedi Jsonix per quello.)

Ok, spero di far luce sul motivo per cui le cose in XJC sono come sono. Buona fortuna con queste API, non sono straghtforward. Sentiti libero di controllare il codice open source esistente, ci sono molti esempi disponibili.

ps. Volevo davvero sempre scrivere questo. :)

+0

In effetti, ottima spiegazione. Il motivo per cui lo chiedo è perché sto migliorando il ['jaxb-xew-plugin'] (https://github.com/dmak/jaxb-xew-plugin/blob/master/src/main/java/com/sun /tools/xjc/addon/xew/XmlElementWrapperPlugin.java), e l'intero algoritmo è un po 'incasinato perché alcune informazioni sono nel modello di struttura e altre nel modello di codice. Forse puoi rispondere alla mia piccola domanda: è possibile imparare che la proprietà data è stata personalizzata ('fieldOutline.getPropertyInfo(). GetCustomizations()' è sempre vuoto)? E in generale, qual è il posto migliore per discutere di questi trucchi? Grazie. –

+0

hi @lexicore, ho aggiunto una domanda, http://stackoverflow.com/questions/32677605/jaxb-how-to-remove-anything-from-jdefinedclass puoi darci un'occhiata. – weima

+0

hai accennato che consente "Consenti strategie diverse di generazione del codice". Quali sono le strategie che possono essere seguite – weima

2

(questo è quello di rispondere alle vostre ulteriori domande.)

Sì, è possibile verificare le personalizzazioni. Here is una classe che sto utilizzando per accedere alle personalizzazioni.

Il trucco è che le proprietà di riferimento non hanno proprie personalizzazioni, le personalizzazioni sono posizionate nelle proprietà dell'elemento di riferimento.

public static CCustomizations getCustomizations(
     final CPropertyInfo propertyInfo) { 

    final CCustomizations main = new CCustomizations(
      propertyInfo.getCustomizations()); 

    final Collection<CCustomizations> elementCustomizations = propertyInfo 
      .accept(new CPropertyVisitor<Collection<CCustomizations>>() { 
       public Collection<CCustomizations> onAttribute(
         CAttributePropertyInfo info) { 
        return Collections.emptyList(); 
       } 

       public Collection<CCustomizations> onElement(
         CElementPropertyInfo arg0) { 
        return Collections.emptyList(); 
       } 

       public Collection<CCustomizations> onReference(
         CReferencePropertyInfo info) { 

        final List<CCustomizations> elementCustomizations = new ArrayList<CCustomizations>(
          info.getElements().size()); 

        for (CElement element : info.getElements()) { 
         if (!(element instanceof CElementInfo && ((CElementInfo) element) 
           .hasClass())) { 
          elementCustomizations.add(element 
            .getCustomizations()); 
         } 
        } 

        return elementCustomizations; 
       } 

       public Collection<CCustomizations> onValue(
         CValuePropertyInfo arg0) { 
        return Collections.emptyList(); 
       }; 

      }); 

    CCustomizations customizations = main; 

    for (CCustomizations e : elementCustomizations) { 
     main.addAll(e); 
    } 

    return customizations; 
} 

Direi [email protected] è un buon posto per tali discussioni.

+0

Infatti 'jaxb-xew-plugin' potrebbe diventare parte del progetto JAXB2 Basics. Perché non è successo molto tempo fa - posso solo chiedermi. Mi piacerebbe se tu potessi in qualche modo promuovere il miglioramento dell'API del modello, per esempio guarda i problemi che ho elencato [una pagina del progetto] (https://github.com/dmak/jaxb-xew-plugin/#algorithm-description). –

+0

Hm, strano. Sto cercando di utilizzare lo snippet di codice che hai fornito, ma la raccolta 'elementCustomizations' è sempre vuota. Ho la sensazione che le personalizzazioni vengano rimosse una volta applicate. La funzione 'getCustomizations()' è passata all'oggetto restituito da 'FieldOutline.getPropertyInfo()'. –

+0

@dma_k Beh, potresti trovarti in qualche strano caso d'angolo, XJC ne è pieno. Questo è davvero il codice che uso per le personalizzazioni in Nozioni di base di JAXB2: https://svn.java.net/svn/jaxb2-commons~svn/basics/trunk/tools/src/main/java/org/jvnet/jaxb2_commons/ util/CustomizationUtils.java – lexicore

Problemi correlati