What is the role of ClassOutline / JClass / CClass in CodeModel?
Asked Answered
G

2

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.

Gladwin answered 12/2, 2012 at 9:26 Comment(0)
G
21

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. :)

Guinness answered 22/2, 2012 at 22:40 Comment(4)
Indeed, great explanation. The reason why I ask is because I am improving the jaxb-xew-plugin, 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.Gladwin
hi @lexicore, i have added a question, #32678105 can you please take a look at it.Sector
you mentioned it allows "Allow different strategies of code generation". what are the strategies which can be followedSector
@Sector Please ask another question on "Allow different strategies of code generation".Guinness
G
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 [email protected] is a good place for such discussions.

Guinness answered 27/3, 2012 at 23:31 Comment(6)
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.Gladwin
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().Gladwin
@Gladwin 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: svn.java.net/svn/jaxb2-commons~svn/basics/trunk/tools/src/main/…Guinness
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, 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.Gladwin
First I tried to search in customizations for element Class (see here), 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). I need the check in this method. Now I do it by comparing old and new value.Gladwin
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 netGuinness

© 2022 - 2024 — McMap. All rights reserved.