Page Edited :
CXF20DOC :
Introduction to Aegis (2.1)
Introduction to Aegis (2.1) has been edited by Benson Margulies (Mar 02, 2008). Content:What is Aegis?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. Aegis began as part of XFire, and moved with XFire into Apache CXF. 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. 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. Getting Started: Basic Use of AegisYou can configure any web service 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 client that you like. You can talk to an Aegis service with JAXB, or .NET, or a scripted language, or ... Aegis itself. 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. 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. For example, here is a Simple front-end service using Aegis as a data binding. <simple:server id="pojoservice" serviceClass="demo.hw.server.HelloWorld" address="/hello_world"> <simple:serviceBean> <bean class="demo.hw.server.HelloWorldImpl" /> </simple:serviceBean> <simple:dataBinding> <bean class="org.apache.cxf.aegis.databinding.AegisDatabinding" /> </simple:dataBinding> </simple:server> </bean>
Aegis can handle all of these. For all except interfaces, there are two mechanisms that involved: the root class list and xsi:type attributes. 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. These type attributes allow Aegis to identify the type of these additional objects and look them up in the mappings. Interfaces require one further step. Obviously, Aegis cannot instantiate (run 'new') on an interface. So 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. 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.) 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. To use additional classes or interfaces, you need to set two (or three) properties of your AegisContext.
Global Type Creation OptionsThere 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. There are four properties in the class, of which two are much more commonly used.
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. Detailed Control of Bean Type MappingThis 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. XML Mapping FilesXML 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. 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 responsibilties of front-ends and databindings, and the Aegis front end can be used to configure the names and parameters of services. The present author is not sure what will happen in the event of a conflict between JAX-WS and Aegis. The Aegis service configuration is best used with the Simple front end. For both bean and service customization, Aegis looks for customization in files found by the classloader. If your class is my.hovercraft.is.full.of.Eels, 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. 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. This is a copy of the XML Schema for mapping XML files that is annotated with comments. Bean mappingHere is a very simple mapping. It takes a property named 'horse', renames it to 'feathers', and makes it an attribute instead of an element. <mappings> <mapping name=""> <property name="horse" mappedName="Feathers" style="attribute"/> </mapping> </mappings> Names and NamespacesYou 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. <mappings xmlns:np="urn:north-pole:operations"> <mapping name="np:Employee"> </mapping> </mappings> 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. This will result in a mapping like so: <np:Employee xmlns:np="urn:north-pole:operations"> <np:Name>Santa Claus</np:Name> <np:Title>Chief Present Officer (CPO)</np:Title> </np:Employee> Ignoring propertiesIf you don't want to serialize a certain property it is easy to ignore it: <mappings> <mapping> <property name="propertyName" ignore="true"/> </mapping> </mappings> MinOccurs and NillableThe 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. <mappings> <mapping> <property name='everpresentProperty' minOccurs='1' nillable='false'/> </mapping> <mappings> Alternative Type BindingLater on, we will explain how to replace the default mappings that Aegis provides for basic types. However, thre 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. 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. <mappings xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <mapping> <property name="birthDate" type="org.apache.cxf.aegis.type.basic.DateType" typeName="xsd:date" /> </mapping> </mappings> CollectionsIf 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. Multiple mappings for Different ServicesWhat 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. Services and ParametersFor a service, mapping files specify attributes of operations and parameters. This example specifies that getUnannotatedStrings returns a return element names 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. <mappings> <mapping> <method name="getUnannotatedStrings"> <return-type name="UnannotatedStringCollection" componentType="java.lang.String"/> </method> <method name="getValues"> <parameter index="0" componentType="java.lang.String"/> </method> </mapping> </mappings> AnnotationsLike 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:
In addition, Aegis will respect actual JAXB annotations from the following list:
Note, however, that Aegis goes not handle package-info.java classes, and so XmlSchema must be applied to a class. Creating Your Own Type MappingsIf 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. To see how these classes work, read the source code. To register your type mappings, you have two choices. 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<?> to your custom mapping object. 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 before the service is initialized. Customizing Type CreationWhat 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. 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. |
Unsubscribe or edit your notifications preferences