SeamFramework.orgCommunity Documentation

Chapter 18. Solder Config XML provider

18.1. XML Namespaces
18.2. Adding, replacing and modifying beans
18.3. Applying annotations using XML
18.4. Configuring Fields
18.4.1. Initial Field Values
18.4.2. Inline Bean Declarations
18.5. Configuring methods
18.6. Configuring the bean constructor
18.7. Overriding the type of an injection point
18.8. Configuring Meta Annotations
18.9. Virtual Producer Fields
18.10. More Information

The main namespace is urn:java:ee. This namespace contains built-in tags and types from core packages. The built-in tags are:

as well as classes from the following packages:

Other namespaces are specified using the following syntax:

        xmlns:my="urn:java:com.mydomain.package1:com.mydomain.package2"

This maps the namespace my to the packages com.mydomain.package1 and com.mydomain.package2. These packages are searched in order to resolve elements in this namespace.

For example, you have a class com.mydomain.package2.Report. To configure a Report bean you would use <my:Report>. Methods and fields on the bean are resolved from the same namespace as the bean itself. It is possible to distinguish between overloaded methods by specifying the parameter types, for more information see Configuring Methods.

By default configuring a bean via XML creates a new bean; however there may be cases where you want to modify an existing bean rather than adding a new one. The <s:replaces> and <s:modifies> tags allow you to do this.

The <s:replaces> tag prevents the existing bean from being installed, and registers a new one with the given configuration. The <s:modifies> tag does the same, except that it merges the annotations on the bean with the annotations defined in XML. Where the same annotation is specified on both the class and in XML the annotation in XML takes precedence. This has almost the same effect as modifying an existing bean, except it is possible to install multiple beans that modify the same class.


<my:Report>
 <s:modifies>
 <my:NewQualifier/>
</my:Report>

<my:ReportDatasource>
 <s:replaces>
 <my:NewQualifier/>
</my:ReportDatasource>

The first entry above adds a new bean with an extra qualifier, in addition to the qualifiers already present, and prevents the existing Report bean from being installed.

The second prevents the existing bean from being installed, and registers a new bean with a single qualifier.

Annotations are resolved in the same way as normal classes. Conceptually, annotations are applied to the object their parent element resolves to. It is possible to set the value of annotation members using the xml attribute that corresponds to the member name. For example:

public @interface OtherQualifier {

   String value1();
   int value2();
   QualifierEnum value();
}

<test:QualifiedBean1>
        <test:OtherQualifier value1="AA" value2="1">A</my:OtherQualifier>
</my:QualifiedBean1>
    
<test:QualifiedBean2>
        <test:OtherQualifier value1="BB" value2="2" value="B" />
</my:QualifiedBean2>

The value member can be set using the inner text of the node, as seen in the first example. Type conversion is performed automatically.

It is possible to both apply qualifiers to and set the initial value of a field. Fields reside in the same namespace as the declaring bean, and the element name must exactly match the field name. For example if we have the following class:

class RobotFactory {

  Robot robot;
}

The following xml will add the @Produces annotation to the robot field:


<my:RobotFactory>
  <my:robot>
    <s:Produces/>
  </my:robot>
</my:RobotFactory/>

Initial field values can be set three different ways as shown below:


<r:MyBean company="Red Hat Inc" />

<r:MyBean>
  <r:company>Red Hat Inc</r:company>
</r:MyBean>

<r:MyBean>
  <r:company>
   <s:value>Red Hat Inc<s:value>
   <r:SomeQualifier/>
  </r:company>
</r:MyBean>

The third form is the only one that also allows you to add annotations such as qualifiers to the field.

It is possible to set Map,Array and Collection field values. Some examples:


<my:ArrayFieldValue>

    <my:intArrayField>
        <s:value>1</s:value>
        <s:value>2</s:value>
    </my:intArrayField>
    
    <my:classArrayField>
        <s:value>java.lang.Integer</s:value>
        <s:value>java.lang.Long</s:value>
    </my:classArrayField>
    
    <my:stringArrayField>
        <s:value>hello</s:value>
        <s:value>world</s:value>
    </my:stringArrayField>
    
</my:ArrayFieldValue>

<my:MapFieldValue>

    <my:map1>
        <s:entry><s:key>1</s:key><s:value>hello</s:value></s:entry>
        <s:entry><s:key>2</s:key><s:value>world</s:value></s:entry>
    </my:map1>
    
    <my:map2>
        <s:e><s:k>1</s:k><s:v>java.lang.Integer</s:v></s:e>
        <s:e><s:k>2</s:k><s:v>java.lang.Long</s:v></s:e>
    </my:map2>
    
</my:MapFieldValue>

Type conversion is done automatically for all primitives and primitive wrappers, Date, Calendar,Enum and Class fields.

The use of EL to set field values is also supported:


<m:Report>
   <m:name>#{reportName}</m:name>
   <m:parameters>
      <s:key>#{paramName}</s:key>
      <s:value>#{paramValue}</s:key>
   </m:parameters>
</m:Report>

Internally, field values are set by wrapping the InjectionTarget for a bean. This means that the expressions are evaluated once, at bean creation time.

It is also possible to configure methods in a similar way to configuring fields:

class MethodBean {


   public int doStuff() {
      return 1;
   }
   public int doStuff(MethodValueBean bean) {
      return bean.value + 1;
   }
   
   public void doStuff(MethodValueBean[][] beans) {
      /*do stuff */
   }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:s="urn:java:ee" 
       xmlns:my="urn:java:org.jboss.solder.config.xml.test.method">
    <my:MethodBean>
    
        <my:doStuff>
            <s:Produces/>
        </my:doStuff>
        
        <my:doStuff>
            <s:Produces/>
            <my:Qualifier1/>
            <s:parameters>
                <my:MethodValueBean>
                    <my:Qualifier2/>
                </my:MethodValueBean>
            </s:parameters>
        </my:doStuff>
        
        <my:doStuff>
            <s:Produces/>
            <my:Qualifier1/>
            <s:parameters>
                <s:array dimensions="2">
                    <my:Qualifier2/>
                    <my:MethodValueBean/>
                </s:array>
            </s:parameters>
        </my:doStuff>
        
    </my:MethodBean>
</beans>

In this example, MethodBean has three methods. They are all named doStuff.

The first <test:doStuff> entry in the XML file configures the method that takes no arguments. The <s:Produces> element makes it into a producer method.

The next entry in the file configures the method that takes a MethodValueBean as a parameter and the final entry configures a method that takes a two dimensional array ofMethodValueBeans as a parameter. For both of these methods, a qualifier was added to the method parameter and they were made into producer methods.

Method parameters are specified inside the <s:parameters> element. If these parameters have annotation children they are taken to be annotations on the parameter.

The corresponding Java declaration for the XML above would be:

class MethodBean {

            
 @Produces
 public int doStuff() {/*method body */}            
             
 @Produces
 @Qualifier1
 public int doStuff(@Qualifier2 MethodValueBean param) {/*method body */}
 
 @Produces
 @Qualifier1
 public int doStuff(@Qualifier2 MethodValueBean[][] param) {/*method body */}
}

Array parameters can be represented using the <s:array> element, with a child element to represent the type of the array. E.g. int method(MethodValueBean[] param); could be configured via xml using the following:


<my:method>
    <s:array>
      <my:MethodValueBean/>
    </s:array>
</my:method>
      

It is also possible to configure the bean constructor in a similar manner. This is done with a <s:parameters> element directly on the bean element. The constructor is resolved in the same way methods are resolved. This constructor will automatically have the @Inject annotation applied to it. Annotations can be applied to the constructor parameters in the same manner as method parameters.


<my:MyBean>
   <s:parameters>
         <s:Integer>
            <my:MyQualifier/>
         </s:Integer>
   </s:parameters>      
</my:MyBean>

The example above is equivalent to the following java:

class MyBean {

   @Inject   
   MyBean(@MyQualifier Integer count)
   {
      ...
   }      
}      

It is possible to limit which bean types are available to inject into a given injection point:

class SomeBean

{
 public Object someField;
}

<my:SomeBean>
        <my:someField>
          <s:Inject/>
          <s:Exact>com.mydomain.InjectedBean</s:Exact>
        </my:someField>
</my:SomeBean>

In the example above, only beans that are assignable to InjectedBean will be eligible for injection into the field. This also works for parameter injection points. This functionality is part of Solder, and the @Exact annotation can be used directly in java.

It is possible to make existing annotations into qualifiers, stereotypes or interceptor bindings.

This configures a stereotype annotation SomeStereotype that has a single interceptor binding and is named:


<my:SomeStereotype>
  <s:Stereotype/>
  <my:InterceptorBinding/>
  <s:Named/>
</my:SomeStereotype>

This configures a qualifier annotation:


<my:SomeQualifier>
  <s:Qualifier/>
</my:SomeQualifier>

This configures an interceptor binding:


<my:SomeInterceptorBinding>
  <s:InterceptorBinding/>
</my:SomeInterceptorBinding>

Solder XML Config supports configuration of virtual producer fields. These allow for configuration of resource producer fields, Solder generic bean and constant values directly via XML. For example:


<s:EntityManager>
  <s:Produces/>
  <s:PersistenceContext unitName="customerPu" />
</s:EntityManager>

<s:String>
  <s:Produces/>
  <my:VersionQualifier />
  <value>Version 1.23</value>
</s:String>

The first example configures a resource producer field. The second configures a bean of type String, with the qualifier @VersionQualifier and the value 'Version 1.23'. The corresponding java for the above XML is:

class SomeClass

{
  @Produces
  @PersistenceContext(unitName="customerPu")
  EntityManager field1;
  
  @Produces
  @VersionQualifier
  String field2 = "Version 1.23";
}

Although these look superficially like normal bean declarations, the <Produces> declaration means it is treated as a producer field instead of a normal bean.

For further information, look at the units tests in the Solder XML Config distribution. Also see the XML-based metadata chapter in the JSR-299 Public Review Draft, which is where this feature was originally proposed.