cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject [CONF] Apache CXF Documentation > Aegis (2.1)
Date Fri, 11 Sep 2009 15:55:00 GMT
    <base href="">
            <link rel="stylesheet" href="/confluence/s/1519/1/1/_/styles/combined.css?spaceKey=CXF20DOC&amp;forWysiwyg=true"
<body style="background-color: white" bgcolor="white">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
     <h2><a href="">Aegis
     <h4>Page <b>edited</b> by             <a href="">Christian
     <div class="notificationGreySide">
         <p>For CXF 2.1 or newer</p>

<h1><a name="Aegis%282.1%29-WhatisAegis%3F"></a>What is Aegis?</h1>

<p>Aegis is a databinding. That is, it is a subsystem that can map Java objects to XML
documents described by XML schema, and vica-versa. Aegis is designed to give useful mappings
with a minimum of programmer effort, while allowing detailed control and customization.</p>

<p>Aegis began as part of XFire, and moved with XFire into Apache CXF.</p>

<p>You can use Aegis independently of CXF as a mechanism for mapping Java objects to
and from XML. This page, however, describes Aegis as used inside of CXF.</p>

<p>Aegis has some advantages over JAXB for some applications. Some users find that it
produces a more natural XML mapping for less configuration. For example, Aegis has a default
setting for 'nillable', allowing you to declare it for your entire service in one place instead
of having to annotate every single element. The biggest advantage of Aegis, however, is a
convenient way to customize the mapping without adding (@)annotations to your Java code. This
allows you to avoid class loading dependencies between your data classes and your web service
binding. </p>

<h1><a name="Aegis%282.1%29-GettingStarted%3ABasicUseofAegis"></a>Getting
Started: Basic Use of Aegis</h1>

<p>You can configure any web <em>service</em> to use the Aegis data binding.
A service configured with Aegis will yield a valid WSDL description, and you can use that
to configure any <em>client</em> that you like. You can talk to an Aegis service
with JAXB, or .NET, or a scripted language, or ... Aegis itself.</p>

<p>You can use Aegis as a client to talk to Aegis, by using the very same Java classes
and configuration files in the client environment that you use on the server. However, it's
not all that practical to use Aegis as a client to talk to some a service using some other
data binding, since Aegis lacks a 'wsdl2java' tool.</p>

<p>Using Aegis on the client side also carries severe risks of compatibility problems.
Since there is no WSDL to specify the contract, small changes in your code or in CXF can result
in a situation where the client and the server are incompatible. If you want to use Aegis
on the client side, you should be sure to use exactly the same version of CXF on both sides.
If you cannot do that, you should consider generating JAX-WS/JAX-B code for the client using

<p>Every CXF service and client uses a front end: JAX-WS, Simple, etc. Each of these
provides a place to configure the data binding, both in Spring and via Java code.</p>

<p>For example, here is a Simple front-end service using Aegis as a data binding.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
  <span class="code-tag">&lt;simple:server id=<span class="code-quote">"pojoservice"</span>
serviceClass=<span class="code-quote">"demo.hw.server.HelloWorld"</span> address=<span
  	<span class="code-tag">&lt;simple:serviceBean&gt;</span>
  		<span class="code-tag">&lt;bean class=<span class="code-quote">"demo.hw.server.HelloWorldImpl"</span>
  	<span class="code-tag">&lt;/simple:serviceBean&gt;</span>
         <span class="code-tag">&lt;simple:dataBinding&gt;</span>
       <span class="code-tag">&lt;bean class=<span class="code-quote">"org.apache.cxf.aegis.databinding.AegisDatabinding"</span>
    <span class="code-tag">&lt;/simple:dataBinding&gt;</span>
  <span class="code-tag">&lt;/simple:server&gt;</span>
 <span class="code-tag">&lt;/bean&gt;</span>

<p>AegisDatabinding is the class that integrates Aegis into CXF as a databinding.</p>

<p>Note that AegisDatabinding beans, like all databinding beans, are <em>not reusable</em>.
The example<br/>
above uses an anonymous nested bean for the databinding. If you make a first-class bean for
a databinding, be sure to use scope='prototype' if you are inclined to define more than one

<h1><a name="Aegis%282.1%29-AegisOperationsTheSimpleCase"></a>Aegis Operations
- The Simple Case</h1>

<p>How does Aegis work? Aegis maintains, for each service, a set of mappings from Java
types (Class&lt;?&gt; objects) to XML Schema types. It uses that mapping to read and
write XML. Let's look at a simple service, where all the Java types involved are either Java
built-in types, other types with predefined mappings to XML Schema, or simple bean-pattern
classes that have properties that (recursively) are simple.</p>

<p>Let's start with <em>serializing</em>: mapping from Java to XML. (JAXB
calls this marshalling, and cannot decide how many 'l's to use in spelling it.) Given a Java
object, Aegis looks to see if it has a mapping. By default, Aegis has a set of <a href="/confluence/display/CXF20DOC/Aegis+Default+Mappings"
title="Aegis Default Mappings">default mappings</a> for the basic types defined in
XML Schema, plus a few other special items. These mappings are implemented by Java classes,
parts of Aegis, that can turn objects in to XML and visa versa. In particular, note that Aegis
will map a DataSource or DataHandler to an MTOM attachment.</p>

<p>What if Aegis finds no mapping for a type? In the default configuration, Aegis invokes
the <em>type creators</em> to create a mapping. Type creators use several mechanisms
to create XML schema from Java objects. This include reflection, annotations, and XML type
mappings files. As part of the mapping process, Aegis will assign a namespace URI based on
the Java package. (<b>Note</b>: Aegis does not support elementForm='unqualified'
at this time.) These mappings are implemented by a generic mapping class, and stored away.</p>

<p>How about the reverse process: <em>deserializing</em>? (JAXB calls this
unmarshalling.) In this case, by default, Aegis is presented with an XML element and asked
to produce a Java object. Recall, however, that the Aegis maintains a mapping from Java types
to XML Schema Types. By default, an XML instance document offers no information as to the
type of a given element. How can Aegis determine the Java type? Outside of CXF, the application
would have to tell Aegis the expected type for the root element of a document. Inside CXF,
however, Aegis gets the benefit of the Message and Part information for the service. The WSDL
service configuration for a service gives enough information to associate an XML Schema type
with each part. Once the front-end has determined the part, it can call Aegis with the QName
for the schema type, and Aegis can look it up in the mapping.</p>

<p>Will it be in the mapping? Yes, because Aegis precreates mappings for the types in
the service's parts. Aegis <em>cannot</em> dynamically create or choose a Java
class based on XML schema, so the type creators cannot start from XML.</p>

<h1><a name="Aegis%282.1%29-UsingJavaClassesThatAren%27tVisibletotheServiceInterface"></a>Using
Java Classes That Aren't Visible to the Service Interface</h1>

<p>Many web service programmers want to use types that are <em>not</em>
directly visible by reflection of the service interface. Here are some popular examples of
types that programmers want to use for property or parameter types:</p>

	<li>Declare a base type, but transfer any one of a number of classes that extend it.</li>
	<li>Declare a raw Collection class, such as a Set, List, or Map, and send arbitrary
objects as keys and values.</li>
	<li>Declare a base exception type for 'throws', and then throw other exception classes
that derive from it.</li>
	<li>Declare an interface or an abstract type.</li>

<p>Aegis can handle all of these. For all except interfaces, there are two mechanisms
involved: the root class list and xsi:type attributes. </p>

<p>As explained above, Aegis can write 'anything', but it can only read objects of types
that are mapped. You must give Aegis a list of all the types that you want to use over and
above those visible from the service, and you must instruct Aegis to send xsi:type attributes
when sending<br/>
objects of such types.<br/>
These type attributes allow Aegis to identify the type of these additional objects and look
them up in the mappings.</p>

<p>Interfaces and abstract types require one further step. Obviously, Aegis cannot instantiate
(run 'new') on an interface. Thus, knowing that a particular XML Schema type maps to an interface
is not enough information. To be able to read an XML element that corresponds to an interface,
Aegis must know a 'proxy class' that implements the interface. You must give Aegis a mapping
from interface types to proxy class names.</p>

<p>How does this work? The core of Aegis is the AegisContext class. Each AegisDatabinding
object has an AegisContext. (It is probably not possible to share an AegisContext amongst
databindings.) </p>

<p>By default, AegisDatabinding will create its own AegisContext with default properties.
To configure additional types, as well control other options that we will examine later on,
you must create the AegisContext for yourself and specify some of its properties. Then you
pass your AegisContext object into your AegisDatabinding object.</p>

<p>To use additional classes or interfaces, you need to set two (or three) properties
of your AegisContext.</p>

	<li><b>rootClasses</b> is a collection of Java Class&lt;?&gt; objects.
These are added to the list of types known to Aegis. Aegis will create a mapping for each.
For convenience, there is a rootClassNames property for use from Spring. It is a list of Strings
containing class names.</li>

	<li><b>writeXsiTypes</b> is a boolean. Set it to <b>true</b>
to send xsi:type attributes.</li>

	<li><b>beanImplementationMap</b> is a mapping from Class&lt;?&gt;
to class names. Use this to specify proxy classes for interfaces (or abstract classes).</li>

<h1><a name="Aegis%282.1%29-GlobalTypeCreationOptions"></a>Global Type Creation

<p>There are a few global options to the default type mapping process. You can control
these by creating a org.apache.cxf.aegis.type.TypeCreationOptions and passing it into your
AegisContext object.</p>

<p>There are four properties in the class, of which two are much more commonly used.

	<li><b>defaultNillable</b> defines the default value of the <b>nillable</b>
attribute of xsd:element items in the xsd:sequences built for non-primitive types. By default,
it is true, since any Java reference can be null. However, nillable='true' has annoying consequences
in some wsdl2java tools (turning scalars into arrays, e.g.), and so many programmers prefer
to default to <b>false</b>.</li>

	<li><b>defaultMinOccurs</b> defines the default value of the <b>minOccurs</b>
attribute of xsd:element items in the xsd:sequences built for Java arrays. In combination
with nillable, programmers often want to adjust this value from 0 to 1 to get a more useful
mapping of an array.</li>

	<li><b>defaultExtensibleElements</b> causes each sequence to end with an
xsd:any. The idea here is to allow for schema evolution; a client that has generated Java
from one version of the service will tolerate data from a newer version that has additional
elements. Use this feature with care; version management of web services is a complex topic,
and xsd:any may have unexpected consequences.</li>

	<li><b>defaultExtensibleAttributes</b> causes each element to permit any
attribute. By default, Aegis doesn't map <b>any</b> properties or parameters to
attributes. As with the element case, care is called for.</li>

<p>Note that these are options to the default type creators. If you take the step of
creating a customized type creator, it will be up to you to respect or ignore these options.</p>

<p>Here's a quick example of Java code setting these options. In Spring you would do
something analogous with properties. </p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
TypeCreationOptions tOpts = <span class="code-keyword">new</span> TypeCreationOptions();
tOpts.setDefaultNillable(<span class="code-keyword">false</span>);
AegisDatabinding aDB = <span class="code-keyword">new</span> AegisDatabinding();

<h1><a name="Aegis%282.1%29-DetailedControlofBeanTypeMapping"></a>Detailed
Control of Bean Type Mapping</h1>

<p>This page has descended, gradually, from depending on Aegis' defaults toward exercising
more detailed control over the process. The next level of detail is to customize the default
type creators' behavior via XML mapping files and annotations.</p>

<h2><a name="Aegis%282.1%29-XMLMappingFiles"></a>XML Mapping Files</h2>

<p>XML mapping files are a major distinguishing feature of Aegis. They allow you to
specify details of the mapping process without either (a) modifying your Java source for your
types or (b) maintaining a central file of some kind containing mapping instructions.</p>

<p>Aegis XML mapping applies to services and to beans. By "beans," we mean "Java classes
that follow the bean pattern, used in a web service." "Services," you ask? Aren't they the
responsibility of the CXF front end? There is some overlap in the responsibilities of front-ends
and databindings.</p>

<p>By and large, front-ends map services to XML schema, filling in XML Schema elements
and types for messages and parts. Data bindings then map from those schema items to Java.
However, Aegis also provides XML configuration for methods and parameters, which 'poach' in
the territory of the front end. This works well for the Simple front end, which has no other
way to control these mappings. The present author is not sure what will happen in the event
of a conflict between Aegis and any other front-end, like JAX-WS, that has explicit configuration.
Thus, Aegis service configuration is best used with the Simple front end.</p>

<p>For both bean and service customization, Aegis looks for customization in files found
by the classloader. If your class is, Aegis will search the
classpath for /my/hovercraft/is/full/of/Eels.aegis.xml. In other words, if Eels.class is sitting
in a JAR file or a directory, Eels.aegis.xml can be sitting right next to it.</p>

<p>Or, on the other hand, it can be in a completely different JAR or tree, so long as
it ends up in the same logical location. In other words, you can create XML files for classes
when you don't even have their source. </p>

<p><a href="/confluence/display/CXF20DOC/Annotated+Aegis+File+Schema" title="Annotated
Aegis File Schema">This</a> is a copy of the XML Schema for mapping XML files that
is annotated with comments.</p>

<h3><a name="Aegis%282.1%29-BeanMapping"></a>Bean Mapping</h3>

<p>Here is a very simple mapping. It takes a property named 'horse', renames it to 'feathers',
and makes it an attribute instead of an element.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;mappings&gt;</span>
  <span class="code-tag">&lt;mapping name=""&gt;</span>
    <span class="code-tag">&lt;property name=<span class="code-quote">"horse"</span>
mappedName=<span class="code-quote">"Feathers"</span> style=<span class="code-quote">"attribute"</span>/&gt;</span>
  <span class="code-tag">&lt;/mapping&gt;</span>
<span class="code-tag">&lt;/mappings&gt;</span>

<h4><a name="Aegis%282.1%29-NamesandNamespaces"></a>Names and Namespaces</h4>

<p>You can also specify the full QName of the bean itself. The following mapping causes
a class to have the QName {urn:north-pole:operations}Employee.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;mappings <span class="code-keyword">xmlns:np</span>=<span
  <span class="code-tag">&lt;mapping name=<span class="code-quote">"np:Employee"</span>&gt;</span>
  <span class="code-tag">&lt;/mapping&gt;</span>
<span class="code-tag">&lt;/mappings&gt;</span>

<p>Notice that the namespace was declared on the mappings element and then the prefix
was used to specify the element QNames for the name/title properties.</p>

<p>This will result in a mapping like so:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;np:Employee <span class="code-keyword">xmlns:np</span>=<span
  <span class="code-tag">&lt;np:Name&gt;</span>Santa Claus<span class="code-tag">&lt;/np:Name&gt;</span>
  <span class="code-tag">&lt;np:Title&gt;</span>Chief Present Officer
(CPO)<span class="code-tag">&lt;/np:Title&gt;</span>
<span class="code-tag">&lt;/np:Employee&gt;</span>

<h4><a name="Aegis%282.1%29-Ignoringproperties"></a>Ignoring properties</h4>

<p>If you don't want to serialize a certain property it is easy to ignore it:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;mappings&gt;</span>
  <span class="code-tag">&lt;mapping&gt;</span>
    <span class="code-tag">&lt;property name=<span class="code-quote">"propertyName"</span>
ignore=<span class="code-quote">"true"</span>/&gt;</span>
  <span class="code-tag">&lt;/mapping&gt;</span>
<span class="code-tag">&lt;/mappings&gt;</span>

<h4><a name="Aegis%282.1%29-MinOccursandNillable"></a>MinOccurs and Nillable</h4>

<p>The default Aegis mapping is to assume that, since any Java object can be null, that
the corresponding schema elements should have minOccurs of 0 and nillable of true. There are
properties on the mappings for to control this.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;mappings&gt;</span>
  <span class="code-tag">&lt;mapping&gt;</span>
    <span class="code-tag">&lt;property name='everpresentProperty' minOccurs='1'
 <span class="code-tag">&lt;/mapping&gt;</span>
<span class="code-tag">&lt;mappings&gt;</span>

<h4><a name="Aegis%282.1%29-AlternativeTypeBinding"></a>Alternative Type

<p>Later on, we will explain how to replace the default mappings that Aegis provides
for basic types. However, there are some cases where you may want to simply specify one of
the provided type mappings for one of your properties. You can do that from the XML mapping
file without creating any Java customization.</p>

<p>By default, for example, if Aegis maps a property as a Date, it uses the XML schema
type xsd:dateTime. Here is an example that uses xsd:date, instead.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;mappings <span class="code-keyword">xmlns:xsd</span>=<span
	<span class="code-tag">&lt;mapping&gt;</span>
		&lt;property name=<span class="code-quote">"birthDate"</span> 
			type=<span class="code-quote">"org.apache.cxf.aegis.type.basic.DateType"</span>

			typeName=<span class="code-quote">"xsd:date"</span>
	<span class="code-tag">&lt;/mapping&gt;</span>
<span class="code-tag">&lt;/mappings&gt;</span>

<h4><a name="Aegis%282.1%29-Collections"></a>Collections</h4>

<p>If you use a 'raw' collection type, Aegis will map it as a collection of xsd:any
particles. If you want the WSDL to show it as a collection of some specific type, the easiest
thing to do is to use Java generics instead of raw types. If, for some reason, you can't do
that, you can use the componentType and keyType attributes of a property to specify the Java
classes. </p>

<h4><a name="Aegis%282.1%29-MultiplemappingsforDifferentServices"></a>Multiple
mappings for Different Services</h4>

<p>What if you want to specify different mapping behavior for different services on
the same types? The 'mapping' element of the file accepts a 'uri' attribute. Each AegisContext
has a 'mappingNamespaceURI' attribute. If a mapping in a .aegis.xml file has a uri attribute,
it must match the current service's uri.</p>

<h3><a name="Aegis%282.1%29-ServicesandParameters"></a>Services and Parameters</h3>

<p>For a service, mapping files specify attributes of operations and parameters.</p>

<p>This example specifies that getUnannotatedStrings returns an element named UnannotatedStringCollection
which is a raw collection of String values. It then specifies the first parameter of getValues
is also a raw collection of String values.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;mappings&gt;</span>
	<span class="code-tag">&lt;mapping&gt;</span>
		<span class="code-tag">&lt;method name=<span class="code-quote">"getUnannotatedStrings"</span>&gt;</span>
			<span class="code-tag">&lt;return-type name=<span class="code-quote">"UnannotatedStringCollection"</span>
componentType=<span class="code-quote">"java.lang.String"</span>/&gt;</span>
		<span class="code-tag">&lt;/method&gt;</span>
        <span class="code-tag">&lt;method name=<span class="code-quote">"getValues"</span>&gt;</span>
         <span class="code-tag">&lt;parameter index=<span class="code-quote">"0"</span>
componentType=<span class="code-quote">"java.lang.String"</span>/&gt;</span>
        <span class="code-tag">&lt;/method&gt;</span>
	<span class="code-tag">&lt;/mapping&gt;</span>
<span class="code-tag">&lt;/mappings&gt;</span>

<h2><a name="Aegis%282.1%29-Annotations"></a>Annotations </h2>

<p>Like JAXB, Aegis supports some Java annotations to control the mapping process. These
attributes are modelled after JAXB. Aegis defines them in the package org.apache.cxf.aegis.type.java5.
They are:</p>


<p>In addition, Aegis will respect actual JAXB annotations from the following list:</p>


<p>Note, however, that Aegis does not handle classes, and so XmlSchema
must be applied to a class.</p>

<h1><a name="Aegis%282.1%29-CreatingYourOwnTypeMappings"></a>Creating Your
Own Type Mappings</h1>

<p>If you want complete control on the mapping between Java and XML, you must create
your own type mappings. To do this, you should make a class that extends org.apache.cxf.aegis.type.Type,
and then you must register it in a type mapping for your service.</p>

<p>To see how these classes work, read the source code.</p>

<p>To register your type mappings, you have two choices.</p>

<p>If you just want to add a custom type mapping into your service, the easiest thing
to do is to retrieve the TypeMapping from the AegisContext, and register your type as a mapping
from Class&lt;?&gt; to your custom mapping object.</p>

<p>If you want complete control over the process, you can create your own TypeMapping.
The class DefaultTypeMapping is the standard type map. You can use these, or you can create
your own implementation of TypeMapping. Set up your type mapping as you like, and install
it in your context <em>before</em> the service is initialized.</p>

<h1><a name="Aegis%282.1%29-CustomizingTypeCreation"></a>Customizing Type

<p>What if you want to change how Aegis builds new type mappings and types from Java
classes? You can create your own TypeCreator, and either put it in the front of the list of
type creators or replace the entire standard list.</p>

<p>As with type mappings, reading the source is the only way to learn the details. Type
creators are associated with type mappings; you can call setTypeCreator on an instance of
DefaultTypeMapping to install yours.</p>

     <div id="commentsSection" class="wiki-content pageSection">
       <div style="float: right;">
            <a href=""
class="grey">Change Notification Preferences</a>

       <a href="">View
       <a href="">View
       <a href=";showCommentArea=true#addcomment">Add

View raw message