8

My question concerns writing JAXB plugins, in particular JAXB codemodel.

What is the role of ClassOutline (and it's companions) and JClass (and companions) and CClass (and companions)? When looking at the list of classes in corresponding packages it is not clear what is chicken and what is egg.

My interpretation is that CClass (CPropertyInfo, CEnumConstant, ...) are created by XJC at first draft parsing of XSD. Then some magic happens and this model is transformed into JClass (JFieldVar, JEnumConstant, ...) and during this transformation customizations are applied. Afterwards plugins are invoked. ClassOutline is used as a bridge between these two models. Altogether looks very complicated.

With these parallel models I believe that the same information can be derived in several ways. For example, class field type:

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

I am looking for verbose explanation of the lifecycle of above mentioned models. Thanks.

lexicore
  • 42,748
  • 17
  • 132
  • 221
dma_k
  • 10,431
  • 16
  • 76
  • 128

2 Answers2

20

Oh, oh, someone is interested in XJC internals. I might be of some help since I've probably developed more JAXB plugins than anyone else (see JAXB2 Basics for instance)

Ok, let's start. In XJC the schema compiler does approximately following

  • Parses the schema
  • Creates the model of the schema (CClass, CPropertyInfo etc.)
  • Creates the outline (ClassOutline, FieldOutline etc.)
  • Renders the code model (JClass, JDefinedClass, JMethod etc.)
  • Writes the physical code (ex.Java files on the disk)

Let's start with the last two.

Java files don't need explanation, I hope.

Code model is also a relativesly easy thing. It is an API which can be used to construct Java code programmatically. You could just use string concatination instead, but it's much more error-prone. With CodeModel you're almost guaranteed to get at least grammatically correct Java code. So I hope this part is also clear. (By the way, I like CodeModel very much. I recently wrote JavaScript Code Model based on ideas from the CodeModel.)

Let's now look at the "model" and the "outline". Model is the result of parsing the incoming schema. It models the constructs of the incoming schema, mainly in terms of "classes" which corresponds to complex types and "properties" which corresponds to elements, attributes and values (ex. when you have a complex type with simple content).

The model should be understand as a logical modelling construct close to XML and schema. As such, it just describes types and properties that they have. It's surely much more complex that how I'm describing it, there's all sorts of exceptions and caveats - starting from wilcard types (xsd:any), substitution groups, enums, built-in types and so on.

Quite interestingly, a sibling of Model is RuntimeTypeInfoSetImpl which is used by JAXB in the runtime. So it's also a type of model - which is however not parsed from the XML Schema but rather from JAXB annotations in classes. The concept is the same. Both Model and RuntimeTypeInfoSetImpl implement the TypeInfoSet interface which is a super-construct. Check interfaces like ClassInfo and PropertyInfo - they have implementation both for compile-time (CClassInfo and CPropertyInfo in XJC) and run-time (RuntimeClassInfoImpl etc. for JAXB RI).

Ok, so when XJC parsed and analysed the schema, you've got the Model. This Model can't produce the code yet. There are, indeed, different strategies of producing the code. You can generate just annotated classes or you can generate interface/implementing class pair like in JAXB 1. The whole code generation thing isn't actually the task of the model. Moreover, there is a number of aspects that are relevant to the physical nature of the Java code, but aren't really relevant for the model. For instance, you have to group classes into packages. This is driven by the packing system of Java, not by the properties of the model itself.

And this is where outlines come into play. You can see outlines as step between the schema model and the code model. You can view outlines as factories for code model elements responsible for organization of the code and generation of JDefinedClasses from CClassInfos.

So you're right, it is indeed very complicated. I am not a Sun/Oracle employee, I did not design it (I know the person who did it, though and respect him very much). I can guess a couple of reasons for certain design decisions, for instance:

  • Use the same interfaces for compile-time and run-time models
  • Allow different strategies of code generation
  • Allow plugins to manipulate the created model

I agree that this design is very complicated, but it has its reasons. One proof for that is that it was actually possible to build a mapping generator for XML-to-JavaScript mappings - basically on the same models. I just had to replace the code generation leaving schema analysis intact. (See Jsonix for that.)

Ok, hopefully I shed some light on why things in XJC are how they are. Good luck with these APIs, they're not straghtforward. Feel free to check existing open-source code, there's a lot of examples available.

ps. Really always wanted to write this. :)

jsosnowski
  • 1,560
  • 3
  • 26
  • 56
lexicore
  • 42,748
  • 17
  • 132
  • 221
  • Indeed, great explanation. The reason why I ask is because I am improving the [`jaxb-xew-plugin`](https://github.com/dmak/jaxb-xew-plugin/blob/master/src/main/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPlugin.java), and the whole algorithms is messed up a bit because some information is in outline model and some in code model. Maybe you can answer my small question: is it possible to learn that given property was customised (`fieldOutline.getPropertyInfo().getCustomizations()` is always empty)? And in general, what is the best place to discuss such tricks? Thanks. – dma_k Mar 06 '12 at 17:33
  • hi @lexicore, i have added a question, http://stackoverflow.com/questions/32677605/jaxb-how-to-remove-anything-from-jdefinedclass can you please take a look at it. – weima Sep 20 '15 at 09:02
  • you mentioned it allows "Allow different strategies of code generation". what are the strategies which can be followed – weima Sep 20 '15 at 10:14
  • 2
    @weima Please ask another question on "Allow different strategies of code generation". – lexicore Sep 21 '15 at 03:40
2

(This is to answer your further questions.)

Yes, it is possible to check customizations. Here is a class I am using to access customizations.

The trick is that reference properties don't have own customizations, customizations are placed in the referenced element properties.

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;
}

I'd say users@jaxb.java.net is a good place for such discussions.

lexicore
  • 42,748
  • 17
  • 132
  • 221
  • Indeed `jaxb-xew-plugin` could become a part of JAXB2 Basics project. Why it didn't happen long time ago – I can only wonder. I would love if you can somehow push forward improvement of model API, for example look at the issues I've listed [a project page](https://github.com/dmak/jaxb-xew-plugin/#algorithm-description). – dma_k Jul 10 '13 at 16:07
  • Hm, strange. I am trying to use the code snippet you have provided, but the collection `elementCustomizations` is always empty. I have a feeling that customizations are removed once they are applied. The function `getCustomizations()` is passed the object returned by `FieldOutline.getPropertyInfo()`. – dma_k Mar 04 '14 at 20:43
  • @dma_k Well, you might be running into some strange corner case, XJC is full of those. This is indeed the code I use for customizations in JAXB2-Basics: https://svn.java.net/svn/jaxb2-commons~svn/basics/trunk/tools/src/main/java/org/jvnet/jaxb2_commons/util/CustomizationUtils.java – lexicore Mar 04 '14 at 21:48
  • Thanks for the comment, your help is invaluable. I have inspected `CustomizationUtils.java` (I admit, I don't understand clearly all parts of it). Let's take a concrete example ([`element-with-customization.xsd`](https://github.com/dmak/jaxb-xew-plugin/blob/master/src/test/resources/com/sun/tools/xjc/addon/xew/element-with-customization.xsd#L39), line 39). Could you try this example within JAXB2-Basics? If it works for you, that means I am trying to locate the customization in a wrong place in the code model. – dma_k Mar 05 '14 at 09:53
  • First I tried to search in customizations for element `Class` ([see here](https://www.dropbox.com/s/2rw05oiylp118ls/customization_class.png)), but they are all empty. Then I looked into element `PostOffice`: it has the property `class` already customized to `classes` but list of customizations is empty ([see here](https://www.dropbox.com/s/e99joolrmq4479t/customization_postoffice.png)). I need the check in [this method](https://github.com/dmak/jaxb-xew-plugin/blob/master/src/main/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPlugin.java#L984). Now I do it by comparing old and new value. – dma_k Mar 05 '14 at 10:07
  • Oh, so you're trying to process the jaxb:property customization, right? The highlighted annotation? These things are indeed completely different animals. They are not treaded as "vendor customizations", may be indeed removed from customization. You have to check the model/outline for these values. Why don't you drop me a mail, I'll help you out with this. Please desribe what you're trying to achive and so on, I might be of help. valikov at gmx net – lexicore Mar 05 '14 at 11:39