: code generator tutorial

Lesson 8: Control Default Enablement

You have now learned how to enable/disable selected types and you have also learned how to exclude types from ever being part of the model. In all the lessons where we imported types into the model you have been able to observe the following code generator behavior:

We called this the "built-in code generator smarts" that help it to make good decisions based on interpreting your intent. But what exactly are these "built-in code generator smarts?"

In this lesson you are going to learn about the rules that govern which types are enabled by default after they have been imported.

The ultimate goal of using the code generator is to generate proxy types in another language. You tell the code generator which Java types you are interested in and the code generator does the rest. Well, not quite. In the real world, any one Java type usually depends on many other Java types. You telling the code generator the types that you really care about might not be sufficient.

What does it mean to "generate a proxy type for the java.lang.String type?" Does that mean that you get one proxy type? What about the methods String inherits from Object? What about the interfaces String implements? Not generating proxy types for those related types could severely limit the usability of our generated String proxy type. Unfortunately, following this logic for all of String's referenced types leads to a combinatorial explosion of types.

This simple example illustrates the problem. In addition to the types that you really care about, there are usually other types required to create a usable proxy API. After all, you're not just interested in a a proxy type with the proper name, you actually want to use the proxy type just like the original. At the same time, you don't want hundreds or thousands of types when you are really only interested in one type. You want to generate what you really need to use your desired type "completely."

Beyond the mere type, you are of course interested in using the fields and methods declared by the type. But which fields and methods do you really want in your proxy types? All declared fields, even the ones declared private in Java? All declared methods, even framework methods like finalize() that you are not supposed to call explicitly?

The answer is not always the same. For most integration projects, you will only be interested in a subset of public fields and methods. For some integration projects, you will require access to (some) private fields or methods as well.

The fact that there are different use cases with different requirements for type, field, or method enablement points towards a need for configurability. It would be a shame if you had to manually override the enablement status of lots of types, fields, or methods because the code generator picks the wrong default for your use case. Therefore the code generator has several properties that allow you to control the default enablement of types, fields, and methods.

Let's find out how this works.

Step by Step Instructions

  1. Start the Code Generator GUI

    To start the code generator, run xmog without the -version argument. Assuming you are still in the code generator's bin directory, simply type:

    xmog
    ./xmog

    If you run into problems please check out the first lesson.

  2. Open the Import Type(s) from Classpath Dialog

    Click the Add class icon toolbar icon or select Import Type(s) from Class Path... from the code generator's Edit menu. You should see this dialog displayed: The import types from classpath dialog

  3. Specify the Types You Want to Import

    We are just going to import all the types in the java.lang package, so we leave the Exclude field blank and enter java.lang.* in the Include field. Press OK.

    You should see something like this: The GUI after import

    You can see that all types from the java.lang package have been imported, but something unexpected happened: even though you specifically asked for all types from java.lang, not all types are enabled. In particular, types like AbstractMethodError, AssertionError, ClassCircularityError, etc. are disabled.

    There is a good reason for this behavior: notice that all the disabled types are Error types. Normally, you are not expected to catch Errors in Java because they represent some type of catastrophic failure that you are not expected to handle. If you are never going to catch them in your proxy application, there probably is no reason to enable them in the first place!

    But how is that rule implemented? Let's look at the "Enabled Types" model property which governs the default-enabled state for types. This property's default value is

    {exclude:'**Error', private:false, protected:false, default:false }

    This means: "Don't enable types whose name ends in Error and don't enable types that are private, protected, or default accessible."

    You could customize that rule to support your own policies. For example, you could prevent the types from certain of your packages from being default enabled, even if they are specifically included in an import command.

    Also note that there are properties governing the default enablement of methods and fields as well.

  4. Create a New Model

    Create a new model by clicking the New Model toolbar button or typing Ctrl-N.

  5. Modify the Enabled Types Model Property

    We are going to disable all exception types as well as all the error types. Modify the model's "Enabled Types" property to the following value by clicking in the edit field and entering:

    {exclude:'**Error,**Exception', private:false, protected:false, default:false }

    The modification is highlighted in blue. This instructs the code generator to also default-disable all types whose name ends with Exception.

  6. Repeat the Import Step

    Repeat Steps 2 and 3 to import the types in the java.lang package. The result should look something like this: The GUI after import

    Note how both Error and Exception types are now disabled after the import operation has taken place without you having to make any further modifications to the enablement state of selected types.

Take-Away Points

  1. Manual Override vs. Default Enablement

    Default enablement and manual enablement overrides have similar effects. When should you use which?

    • Use default enablement rules to cover enablement "policies" based on element characteristics like name patterns, element accessibility, etc.
    • Use enablement overrides for exceptions to the rule.
  2. All elements in the model can be enabled or disabled.