Overriding mapping of EJB data to XML

When we use an EJB reference or the Spring component in SOA Suite, we usually want to wire it to a non-Java resource. When we do this, JDeveloper uses JAXB to create an XML representation of the parameters and return values of the methods in the Java interface we are using. Often the SOA developer is unable to modify or create mappings in EJB or Java bean itself. If we are unable to change the JAXB mapping in the EJB or Java bean, or there are no mappings provided, and we are using default mappings, then we can use this recipe to override the mappings. Overriding the default generation of the mappings allows us to specify target namespaces, rationalize the structure of the data, and remove unneeded properties from the Java classes. Some things that we may want to customize include:

  • Specifying concrete implementations for abstract classes and interfaces in the interface

    This allows us to map to the Java objects in the interface that cannot be instantiated directly. For example, often we have lists of abstract classes or interfaces; by specifying the possible concrete implementations of these classes, we can generate an XML Schema that includes additional properties available only through the concrete classes.

  • Hiding unwanted properties

    This allows us to remove properties that are not needed for our implementation, or not needed because they are convenience properties, such as the length of an array or collection, which can easily be derived from the underlying array or collection.

  • Providing wrappers for arrays and collections

    The default mapping for an array or collection is to provide a list of repeating elements. We can modify the mapping to provide a wrapper element that represents the whole array or collection, with the repeating elements appearing a level down within it.

  • Changing WSDL namespaces

    It is often necessary to change the namespaces in a generated WSDL to match a corporate standard, or to avoid conflicts with other components that are being used.

SOA Suite allows us to describe in an XML document how we want a Java interface to be mapped from Java objects into XML. The file that does this is called an Extended Mapping (EXM) file. When generating a WSDL and its associated XML Schema from a Java interface, SOA Suite looks for an EXM file corresponding to the Java interface that is being generated. Without this file, the mapping will be the default generation, which simply attempts to take each field and method in the Java code and map it to an XML type in the resulting WSDL. The EXM file is used to describe, or clarify, the mappings to XML, and uses EclipseLink MOXy to provide an XML version of the Java annotations. This means that we can apply the equivalent of the Java annotations to the Java classes referenced from the interface, giving us complete control over how the XML is generated. This is illustrated in the following diagram, which shows how the WSDL interface mapping depends on the Java interface of the EJB reference or Spring component that is being wired (obviously), but is modified by the EXM file that, in turn, may embed or reference an XML version of the JAXB annotations (using EclipseLink MOXy):

Overriding mapping of EJB data to XML

The mapping will automatically take advantage of any class annotations in the Java classes that are being mapped, but the XML descriptions can override or add to these annotations, allowing us fine-grained control over our XML interface. This allows for changes to be made without touching the underlying Java code.

Getting ready

We must identify the Java interface that we wish to override the mapping for, and understand how we wish that interface to be represented in XML. We will use the following Java interface:

package soa.cookbook;

public interface QuoteInterface {
  public QuoteResponse getQuotes(QuoteRequest request);
}

The structure of the request and response parameters is shown in the following diagram:

Getting ready

We want to create a mapping file to modify the way the interface is mapped.

How to do it...

  1. Prepare JDeveloper to use the SOA JAXB mappings.

    To take full advantage of the XML element completion in JDeveloper, we must make sure that all the schema we are using are registered with JDeveloper. Under JDeveloper in Tools | Preferences | XML Schemas, we click on Add to register the schema as an XML extension:

    How to do it...

    The schema is found in a JAR file located at <JDEV_HOME>/modules/org.eclipse.persistence_1.1.0.0_2-1.jar, and the schema is inside this jar at /xsd/eclipselink_oxm_2_1.xsd, so the location we register is

    jar:file:/<JDEV_HOME>/modules/org.eclipse.persistence_1.1.0.0_2-1.jar!/xsd/eclipselink_oxm_2_1.xsd where <JDEV_HOME> is the location where you installed JDeveloper. Note, that the version number of the JAR file and the XML Schema vary between JDeveloper releases:

    How to do it...
  2. Change the order of the source paths in your SOA project to have SCA-INF/src first. This is done using the Project Source Paths dialog in Project Properties. All files related to the mapping will go here. For example, <Project>/SCA-INF/src/com/customer/EXM_Mapping_EJB.exm, where com.customer is the associated Java package:
    How to do it...
  3. Create an EXM mapping file by launching the wizard to generate a base mapping (EXM) file.

    Launch the New XML Document from XML Schema wizard (File | New | All Technologies | General | XML Document from XML Schema).

  4. Specify a file with the name of the Java interface and a .exm extension in a directory corresponding to the Java package of the interface under SCA-INF/src. For example, if your EJB adapter defined soa.cookbook.QuoteInterface as the remote interface, then the directory should be <Project>/SCA-INF/src/soa/cookbook and so the full file path would be <Project>/SCA-INF/src/soa/cookbook/QuoteInterface.exm. By using the .exm extension, we are able to use registered schema that will automatically map to the correct schema so that the future steps in the wizard will understand what we are doing:
    How to do it...

    The weblogic-wsee-databinding schema should already be selected; select a root element of java-wsdl-mapping and leave Depth at the default value. This will give us a basic file to start working with:

    How to do it...
  5. Import a JAXB (OXM) mapping file.

    As recommended by Oracle, separate out the mappings per package by using the <toplink-oxm-file> element. This will allow you, per package, to define reusable mapping files outside of the EXM file. Since the EXM file and the embedded mappings have different XML root elements, defining them separately allows JDeveloper to provide validation and completion; a sample include is shown as follows:

    <?xml version="1.0" encoding="UTF-8" ?>
    <java-wsdl-mapping xmlns="http://xmlns.oracle.com/weblogic/weblogic-wsee-databinding">
      <xml-schema-mapping>
        <toplink-oxm-file file-path="./mappings.xml"
                          java-package="soa.cookbook"/>
      </xml-schema-mapping>
    </java-wsdl-mapping>
  6. Create an OXM file.

    Create an OXM mapping file to store custom mappings. As mentioned, these files are per package, separate from the EXM files, and reusable. We can use the New XML Document from Schema to create these as well. In this case, they will have an XML or OXM extension, use the persistence registered schema (http://www.eclipse.org/eclipselink/xsds/persistence/oxm), and be stored relative to the EXM file. That is, they can go in the same directory, or in other directories, as long as you refer to them by the relative path from the EXM file. In the following example, we have set the target namespace of the mapping.

    <?xml version="1.0" encoding="UTF-8" ?>
    <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
      <!-- Set target Namespace via namespace attribute -->
      <xml-schema namespace=http://cookbook.soa.mapping/javatypes
                  element-form-default="QUALIFIED"/>
    </xml-bindings>
  7. Rewire the existing components.

    Once complete, delete any existing wires to the Java components and rewire. You should notice the dialog box change to indicate that an extended mapping file was used:

    How to do it...

    Note that an extended mapping file was used.

How it works...

When a component that expects a WSDL interface is wired to a component/reference exposing a Java interface, JDeveloper will invoke the Java to the WSDL compiler. This will check the classpath to see if an EXM file exists in the path corresponding to the interface package and with a name corresponding to the interface class. If such a file exists, then it is used to override the default mappings. This file will also override any explicit JAXB annotations in the classes that are to be mapped.

This same process is done at design time in JDeveloper and again at runtime in SOA Suite. At runtime, the mapping is done the first time that the Java component is invoked.

There's more...

XML Schema can also be registered to work as an OXM extension instead of an XML extension. But if you use a .oxm extension, then in each project where you use it you must add a rule to copy .oxm files from the source to the output directory when compiling.

By using a common mapping file or files, it is possible to have consistent mapping across multiple interfaces that use the same classes. By using a different mapping file, it is possible to map classes differently depending on the interface they are used with, allowing the interface to be simplified; for example, by ignoring the properties of a class that are not needed in a given interface.

The EXMMapping project in the code samples has sample EXM (EXM_Mapping_EJB.exm) and OXM files (mappings.xml) demonstrating this.

See also

  • The Ignoring a Java property recipe in this chapter
  • The Creating a wrapper element for a Java collection or array recipe in this chapter
  • The Handling an abstract class recipe in this chapter
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.178.181