Nuts Tags

Basic Nuts tags

value

<value> tag is the simplest tag. It is used to declare a value or a reference.
The following xml declares a value "hello".

<value val="hello"/>

The "type" attribute can be used to specify the type of the literal:

<value val="10" type="int"/>

To reference a variable x:

<value val="$x"/>

When used to reference a variable, <value> is similar to the <alias> tag in the Spring framework.

ctor

The ctor tag describes a constructor call. Component instance is instantiated by calling a constructor.

Let's see an example:

<ctor id="account" class="com.ajoo.BankAccount"/>

Hopefully the xml is self-explained. The "id" attribute is the id that we
can use to refer back to it later. The "class" attribute is the class name.

The above code works when the BankAccount class has only one public constructor. Adding an additional public constructor will cause an ambiguity.
To be explicit, parameter types can be specified as:

<ctor id="account" class="com.ajoo.BankAccount"
    params="int,java.lang.String"/>

This instructs Nuts to look for a constructor with two parameters whose types are int and String.

The above code is not complete though because it expects two parameters while none is specified.

It could be changed slightly to enable auto-wiring where Nuts automatically lookup the container to find a match for the parameter value:

<ctor id="account" class="com.ajoo.BankAccount"
    params="int,java.lang.String" autowire="bytype"/>

Auto-wiring, though looks convenient, is discouraged because it tends to break the predictability of the system. One may easily lose track of what exactly is wired to what.

In order to explicitly specify the arguments, we can:

<ctor id="account" class="com.ajoo.BankAccount"
    params="int,java.lang.String">
  <arg ind="0" val="1"/>
  <arg ind="1" val="hello world"/>
</ctor>

Or, use the "args" tag to save from writing the "ind" attributes:

<ctor id="account" class="com.ajoo.BankAccount"
    params="int,java.lang.String">
  <args>
    <value val="1"/>
    <value val="hello world"/>
  </args>
</ctor>

Even more convenient, using Concise Collection Literal, simple argument values can be specified with a string literal using the "args" attribute. For example:

<ctor id="account" class="com.ajoo.BankAccount"
  params="int,java.lang.String" args="1, hello world"/>

Plus, when arguments are explicitly provided, the number of the actual arguments is also used to disambiguate methods.
For the above code, the "params" attribute can be omitted as long as there's only one 2-parameter constructor. The code then becomes:

<ctor id="account" class="com.ajoo.BankAccount"
    args="1, hello world"/>

Java Bean Properties, when specified, can additionally set properties against the instance created by the constructor.
For example:

<ctor id="account" class="com.ajoo.BankAccount"
    args="1, hello world" props="{type=Saving}"/>

For detailed discussion on Java Bean related attributes and sub-elements, please see the following <bean> tag section.

There are only two difference between <ctor> and <bean>:

  1. <bean> by default uses the parameter-less constructor, while <ctor> requires that only one qualified constructor is present.
  2. when "property-names" is not specified and no property values are specified either, <bean> tries to set all properties, while <ctor> does not set any property.

bean

The bean tag describes a Java Bean component. The simplest form of bean tag is:

<bean id="account" class="com.ajoo.BankAccount"/>

Since the default wiring strategy is manual, this bean will not try to set any property because we didn't specify any.

We can use the same "autowire" attribute to instruct the framework to do auto-wiring:

<bean id="account" class="com.ajoo.BankAccount" autowire="bytype"/>

The default autowiring strategy is bytype. If the BankAccount class has a property named "balance", whose type is int, the framework will automatically search a component whose type is int for it.

Nuts provide a few other autowiring strategies: byName, byQualifiedName and autodetect.

The "byName" strategy instructs the framework to look for a component named "balance" for the property "balance".

The "byQualifiedName" strategy instructs the framework to look for name "com.ajoo.BankAccount.balance" for the "balance" property of the BankAccount component.

The "autodetect" strategy is a sequential combination of "bytype", "byname" and "byqualifiedname", where "bytype" is tried first, and then "byname" and "byqualifiedname" are tried subsequently until a qualified component is found.

Custom autowire modes can also be registered and used. Please see Custom Autowire Mode - EJB3 style for further discussion.

In contrast, there's "manual-wire" that allows us explicitly specify parameters and properties. Let's try explicitly specifying the properties:

<bean id="account" class="com.ajoo.BankAccount">
  <prop key="balance" val="100"/>
  <prop key="id" val="abc"/>
</bean>

Or, using Concise Collection Literal:

<bean id="account" class="com.ajoo.BankAccount"
    props="{balance=100, id=abc}"/>

Isn't that simpler?

There's also a "property-names" attribute that worths mentioning. This attribute can be used to explicitly specify properties that need to be set. When the value for some of the properties are not specified, or when a property cannot be resolved using autowire, an error will be reported.

"property-names" can also be set to "*", which means all properties should be set.

By default, Nuts will check the "property-names" and all the property keys specified using "props" attribute or "prop" sub-element. So if an non-existent property name is specified, Nuts will report error. An optional "validate-property-names" attribute can be set to "false" to suppress such validation. For example:

<bean class="BankAccount" props="{balance=100,id=abc,invalid_property=xyz}"
    validate-property-names="false"/>

The non-existent property name "invalid_property" will be silently ignored.

"optional-properties" is another useful attribute. It somewhat overrides the "property-names" attribute in the sense that even if a property is not specified or cannot be resolved, no error will be reported and the property is silently ignored.

Sometimes, we may have a not-so-bean class that has no default public constructor. Or, maybe we just don't want to call this default constructor.
Suppose I have a constructor with a parameter "id", and I want the component to be like ths Java code:

BankAccount account0 = new BankAccount("abc");
  account0.setBalance(100);

the bean tag can be written as:

<bean id="account" class="com.ajoo.BankAccount"
    args="0" props="{balance=100}"/>

In fact, all the attribues and sub-elements of <ctor> can be used in <bean> with the same syntax and semantics.

Let's get the problem a bit more trickier. We want to call setters against additional Java Bean properties of the object created by yet another bean. We could say:

<bean id="account0" class="com.ajoo.BankAccount" props="{id=abc}"/>
<bean id="account" component="$account0" props="{balance=100}"/>

The "component" attribute of bean is used to reference another component to create the BankAccount object, we then call the Java bean setters to set the additional dependencies.

The $account0 is Nuts' way to indicate a reference. Anything that starts with a '$' indicates a reference. It tells the framework that this "account0" is no literal text, but a reference to another component with this id.

The above solution requires a separate definition of "account0". It is useful when we want to reuse "account0" in different places. When reusing "account0" is not needed, we can use nested component to simplify:

<bean id="account" props="{balance=100}">
  <bean class="com.ajoo.BankAccount" props="{id=abc}"/>
</bean>

method

Nuts allows any Java method to be specified as a step to instantiate component. Assume class BankAccount has a static method "create" that creates a BankAccount object:

public static BankAccount create(String id){
  return new BankAccount(id);
}

We can use this method with the following syntax:

<method id="acct" class="com.ajoo.BankAccount" name="create">
  <arg ind="0" val="abc"/>
</method>

As usual, we prefer manual-wiring. But keep in mind that the "autowire" attribute can be specified for any component, ctor, bean, method and all the subsequent tags we are going to talk about.

In fact, this syntax is very similar to that of ctor. And it is pretty self-explained. The "class" attribute tells the class to use. The "name" attribute tells which method to call.

In order to preclude ambiguity, the "params" attribute can be used as:

<method id="acct" class="com.ajoo.BankAccount" name="create"
      params="java.lang.String">
  <arg ind="0" val="abc"/>
</method>

Similar to bean, we can also call non-static methods against the component instance created by another component. Now let's say I want to call the "cloneBankAccount" method in the BankAccount class. This method is not static, so a slightly different syntax needs to be used:

<method id="acct" class="com.ajoo.BankAccount" name="create"
    params="java.lang.String">
  <arg ind="0" val="abc"/>
</method>
<method id="acct'" component="$acct" name="cloneBankAccount" params=""/>

The "acct'" component will first invoke the "acct" component to create the BankAccount object via the "create" method. It then calls the parameter-less "cloneBankAccount" method to clone a BankAccount object.

The "acct" component can also be nested in the "acct'" component:

<method id="acct'" name="cloneBankAccount" params="">
  <method id="acct" class="com.ajoo.BankAccount" name="create"
      params="java.lang.String">
    <arg ind="0" val="abc"/>
  </method>
</method>

In fact, <ctor>, <bean>, <getter>, <field> and <method> can all be nested inside <method> as the instance to invoke the method against.

Using Concise Collection Literal, simple argument values can be specified with a string literal using the "args" attribute. For example:

<method id="acct" class="com.ajoo.BankAccount"
    name="createWithIdAndBalance" args="abc, 10"/>

Java Bean properties, if specified, can be additionally set against the returned instance using the "props" attribute or <prop>, <props> sub-elements. Please see the discussion of <bean> tag for all Java Bean related attributes and sub-elements.

field

In order to mimic the following Java code:

new SimpleLogger(System.out);

Nuts' syntax can be:

<ctor id="logger" class="com.ajoo.SimpleLogger">
  <arg ind="0">
    <field class="java.lang.System" name="out"/>
  </arg>
</ctor>

Not surprisingly, field has the same syntax as method, bean to support accessing instance fields. The following syntax reads the "out" field from the SimpleLogger object:

<field id="logger.out" component="$logger" name="out"/>

field supports multi-level field access. For the following Java code:

logger.a.b.c.d

Nuts syntax is:

<field id="logger.a.b.c.d" component="$logger" name="a.b.c.d"/>

getter

The getter tag can be used to access Java Bean getter.
getter's syntax is very similar to that of field. Assume the Logger object doesn't expose the fields directly, but exposes getA(), getB(), getC(), getD() instead. The nuts' syntax is:

<getter id="logger.a.b.c.d" component="$logger" name="a.b.c.d"/>

getter does support indexed property though. In order to get the number 3 sub-account, we can:

<getter id="sub3" component="$account" name="subAccount" ind="2"/>

Note, the index is 0-based.

setter

Well, we can't just give you "getter" without setter. In order to set the "out" property of the logger object, we can:

<setter id="set stdout to logger" component="$logger" name="out">
  <field class="java.lang.System" name="out"/>
</setter>

To set the first sub-account of the account component, we do:

<setter id="set 1st sub-account" component="$account"
    name="subAccount" ind="0"
    val="$some other account that we omit here"
/>

null

"null" is not a tag but a variable.

It is a predefined variable that you can use "$null" to refer to. For example:

<ctor id="acct" class="BankAccount" props="{joint_account=$null}"/>

The above configuration is equivalent to:

BankAccount acct = new BankAccount();
acct.setJoint(null);

yan

"yan" is another variable that points to the current container. This variable can be used to inject the current container to components that want to be aware of the container, though this is typically discouraged for the intrusion it introduces to the component.

resource_loader

"resource_loader" is yet another variable that points to the "jfun.yan.util.resource.ResourceLoader" object that's used to load resources. This variable can be used to inject the ResourceLoader object into components that want to be aware of the ResourceLoader. For the same intrusion reason, it should be considered the last resort.

variable vs. string interpolation

Nuts supports both straight variable (without conversion to string) and string interpolation (auto-conversion to string). When a string or a substring within a collection literal starts with '$', it may indicate either a variable or a string interpolation.

String interpolation is distinguished from variable by the use of a '{' after the '$' character. So that "${varname}" is a string interpolation that results in a string, while "$varname" is a the variable itself.

body

<body> tag encloses all the components declared in the configuration file. Only one <body> tag is allowed per configuration file. For example:

<body singleton="true" autowire="none">
  <ctor id="a" .../>
  <method id="b" .../>
  <field id="c" .../>
</body>

<body> tag supports several attributes:

  • singleton specifies the global default setting for singleton. The value could be "true", "false" or "thread". "thread" means that each thread get a different copy of the singleton instance. This default setting only affects components defined in the global scope. Local components and sub components are by default prototype.
  • autowire specifies the global default setting for autowiring strategy. Valid values are "none", "false", "off", "no", "bytype", "byname", "byQualifiedName" and "autodetect".
  • eager-init specifies the default global setting for eager instantiation. The value can be "true", "false", "on", "off", "yes", "no". "false" is used when not specified, which means components are by default lazily instantiated.

import

<import> tag is used to import contents from another module file. For example:

<import file="basic_components.xml" includes="a,b,c*" excludes="cat*"
    namespace="basic"/>
<import resource="basic_components.xml" classpath="basic.jar" includes="*"/>

The attributes of <import> tag are:

  • includes Mandatory attribute. It determines which components are included in this import. Either "*" or explicit list of names have to be specified. Wildcard can be appended to any valid id to denote a search by prefix.
  • excludes Optional attribute. The syntax is same as "includes" except it specifies the list of names excluded from the import.
  • namespace Optional attribute. If "namespace" is not specified, the components imported are directly put into the global namespace. When it is specified, for example, namespace="my" is specified, all components imported will be named in the pattern "my.xxx" where xxx is the original name defined in the original file.
  • file. Denotes the filename to be imported. The path is relative to the location of the current configuration file.
  • resource. Denotes the name of a resource that can be loaded from either the current class loader or an alternative class path. "file" and "resource" cannot be both specified.
  • classpath The alternative class path to search for the resource. This attribute can only be specified when "resource" is specified.

module

<module> is the top-most level tag for each configuration file. A complete example of a configuration file may look like:

<module name="test application" description="this is a test application configuration"
    export="a,b,c" depends="x,y"
>
<import file="helper.xml" includes="m,n"/>
<nut name="if" class="jfun.yan.xml.nuts.optional.IfElseNut"/>
<nut name="switch" class="jfun.yan.xml.nuts.optional.SwitchNut"/>
<body>
  <ctor id="a" .../>
  <ctor id="b" class="B">
    <args>
      <value val="$x"/>
      <value val="$y"/>
    </args>
  </ctor>
  <sequence id="c">
    ...
    <if cond="$x" then="$consequence" else="$alternative"/>
    ...
  </sequence>
</body>
</module>
  • <module> tag supports the following attributes:
    • name The name of the module.
    • description Optional attribute. The description of the module.
    • export Optional attribute. It is used to specify which components are going to be visible to the outside. If omitted or specified as "*", all global components will be exported.
    • hide Optional attribute. It is used to specify which components are excluded from the export list. It overrides the export list.
    • depends Optional attribute. Declares components that are not defined by the module but instead provided by the container.
  • Inside the module tag, there are 0 or more <import> tag that imports components defined in other module files.
  • Inside the module tag, there are 0 or more <nut> tag that loads customized nut tags.
  • The <body> tag is the last sub-element inside <module>.

nut

<nut> tag is used to load custom tags. Supported attributes are:

  • name. The name of the tag.
  • class. The fully qualified class name of the Nut class.
  • classpath. Optional attribute. To provide an additional classpath (a list of jar files for example).

Advanced Tags

Labels

 
(None)