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:
- By default, the types that you asked for are enabled.
- Some other types, but not most other types, are enabled as well.
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
- Start the Code Generator GUI
To start the code generator, run
xmog
without the-version
argument. Assuming you are still in the code generator'sbin
directory, simply type:xmog
./xmog
If you run into problems please check out the first lesson.
- Open the Import Type(s) from Classpath Dialog
Click the toolbar icon or select Import Type(s) from Class Path... from the code generator's Edit menu. You should see this dialog displayed:
- 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 enterjava.lang.*
in the Include field. Press OK.You should see something like this:
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 fromjava.lang
, not all types are enabled. In particular, types likeAbstractMethodError
,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 catchErrors
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.
- Create a New Model
Create a new model by clicking the toolbar button or typing
Ctrl-N
. - 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
. - 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:Note how both
Error
andException
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
- 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.
- All elements in the model can be enabled or disabled.