Qual è il ruolo di ClassOutline / JClass / CClass in CodeModel?

La mia domanda riguarda la scrittura di plugin JAXB, in particolare il codemodel JAXB.

Qual è il ruolo di ClassOutline (e dei suoi compagni ) e JClass (e compagni ) e CClass (e compagni )? 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. Poi 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 è usato 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 della class:

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

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

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

Ok iniziamo. In XJC il compilatore dello schema fa approssimativamente il seguente

  • Analizza lo schema
  • Crea il modello dello schema (CClass, CPropertyInfo ecc.)
  • Crea il contorno (ClassOutline, FieldOutline ecc.)
  • Esegue il rendering del modello di codice (JClass, JDefinedClass, JMethod ecc.)
  • Scrive il codice fisico (file ex.Java sul disco)

Iniziamo con gli ultimi due.

I file Java non hanno bisogno di spiegazioni, spero.

Il modello di codice è anche una cosa relativamente facile. È un’API che può essere utilizzata per build 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 il CodeModel. Recentemente ho scritto il codice JavaScript Model basato sulle idee del CodeModel.)

Diamo ora un’occhiata al “modello” e al “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 (ad esempio quando si dispone di un tipo complesso con contenuto semplice).

Il modello dovrebbe 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.

Molto interessante, un fratello di Model è RuntimeTypeInfoSetImpl che viene 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. Sia Model che 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 per la fase di esecuzione ( RuntimeClassInfoImpl ecc. Per JAXB RI).

Ok, quindi quando XJC ha analizzato e analizzato lo schema, hai il Model . Questo Model non può ancora produrre il codice. Esistono, infatti, diverse strategie per produrre il codice. È ansible 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. È ansible visualizzare i contorni come passaggio tra il modello dello schema e il modello di codice. È ansible visualizzare i contorni come fabbriche per gli elementi del modello di codice responsabili dell’organizzazione del codice e della generazione di JDefinedClass 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 indovinare un paio di motivi per alcune decisioni di progettazione, ad esempio:

  • Utilizzare le stesse interfacce per i modelli in fase di compilazione e in fase di esecuzione
  • Consentire diverse strategie di generazione del codice
  • Consenti ai plug-in di manipolare il modello creato

Sono d’accordo che questo progetto è molto complicato, ma ha le sue ragioni. Una prova è che è stato effettivamente ansible 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. 🙂

(Questo è per rispondere alle tue ulteriori domande.)

Sì, è ansible controllare le personalizzazioni. Ecco una class che sto usando 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 elementCustomizations = propertyInfo .accept(new CPropertyVisitor>() { public Collection onAttribute( CAttributePropertyInfo info) { return Collections.emptyList(); } public Collection onElement( CElementPropertyInfo arg0) { return Collections.emptyList(); } public Collection onReference( CReferencePropertyInfo info) { final List elementCustomizations = new ArrayList( info.getElements().size()); for (CElement element : info.getElements()) { if (!(element instanceof CElementInfo && ((CElementInfo) element) .hasClass())) { elementCustomizations.add(element .getCustomizations()); } } return elementCustomizations; } public Collection onValue( CValuePropertyInfo arg0) { return Collections.emptyList(); }; }); CCustomizations customizations = main; for (CCustomizations e : elementCustomizations) { main.addAll(e); } return customizations; } 

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