axis-java-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "tom ONeill" <beagleboythefi...@hotmail.com>
Subject RE: Deserializing XML w/o using client stubs
Date Tue, 28 Sep 2004 12:54:23 GMT
Hi,

I am currently using Axis 1.1. There is nothing stopping me moving to Axis 
1.2-beta other than the fact that I have no information on how stable the 
beta release is. Do you (or anybody else) have any opinions on the relative 
stability of Axis 1.1 versus Axis 1.2.

The XML string which I receive is generated by a mainframe application which 
does a conversion between an old proprietary data format and XML.

In your code you mention that it is not necessary to register Axis classes 
explicitly in Axis 1.2 - that Axis 1.2 can do this dynamically. In that case 
I probably need to use Axis 1.2 as this is functionality that I would 
require. I cannot use a hardcoded list of data classes (as done in the 
sample code provided) as I have no control over the contents of the WSDL 
file (which is defined by an external partner) so its possible that the 
required datatypes can (and do) change regularly. Of course it would be 
possible to use a hardcoded array of the type classes if we were to use the 
WSDL file along with an XSL file to generate our 
serializsation/deserialization source code but I would prefer not to have to 
do this. If Axis 1.2 can handle the datatype registration dynamically then 
this would be preferable. Do you know how this dynamic registration is 
provided in Axis 1.2? Axis does not seem to provide any release notes 
detailing functionality changes from one release to the next?

Michael thanks very much for the sample code as it is exactly what I was 
looking for :)

Regards,
Tom






>From: "Michael Binz" <michab66@gmx.de>
>To: axis-user@ws.apache.org
>CC: beagleboythefirst@hotmail.com
>Subject: RE: Deserializing XML w/o using client stubs
>Date: Tue, 28 Sep 2004 10:45:08 +0200 (MEST)
>
>Tom,
>
>you're not saying for which version of Axis you need a solution, and how 
>the
>XML string that you receive is generated.
>
>The code below is a complete example that we use to serialise and
>deserialise Axis-generated classes.
>
>We use this code to write WebService requests to files that can be later-on
>used to perform regression testing, i.e. the files are deserialised into a
>request structure that is then sent to the server.
>
>The code is for Axis 1.1, the main problem with Axis 1.1 is that we have to
>manually create a TypeMapping holding references to the generated classes,
>with Axis 1.2 this would not be necessary.
>
>The interesting entry points in the code are xmlToAxis() which transforms
>from an XML file to an  instance of the passed class and axisToXml() which
>transforms from an instance of an Axis stub to the XML string.  This is
>symmetric, the string that comes out of axisToXml() can be fed again into
>xmlToAxis() to get the equivalent object structure.
>
>Most bits and pieces in the code are collected from this mailing list.
>
>Hope that helps,
>Michael.
>
>
>
>=== START ===
>package .util;
>
>import java.io.IOException;
>import java.io.StringReader;
>import java.io.StringWriter;
>import java.io.ByteArrayInputStream;
>
>import java.lang.reflect.Method;
>import java.util.Date;
>import java.util.Properties;
>import java.util.StringTokenizer;
>
>import javax.xml.namespace.QName;
>import javax.xml.rpc.encoding.TypeMapping;
>
>import net.guardean.agw.*;
>import net.guardean.agw.server.AgTransformer;
>import net.guardean.agw.ws.schema.*;
>
>import org.apache.axis.MessageContext;
>import org.apache.axis.client.AxisClient;
>import org.apache.axis.client.Call;
>import org.apache.axis.description.TypeDesc;
>import org.apache.axis.encoding.DeserializationContextImpl;
>import org.apache.axis.encoding.SerializationContextImpl;
>import org.apache.axis.message.RPCElement;
>import org.apache.axis.message.SOAPEnvelope;
>import org.apache.axis.message.SOAPBodyElement;
>import org.xml.sax.InputSource;
>import org.xml.sax.helpers.AttributesImpl;
>
>import org.apache.commons.logging.Log;
>import org.apache.commons.logging.LogFactory;
>
>import org.apache.axis.encoding.ser.BaseDeserializerFactory;
>import org.apache.axis.encoding.ser.BaseSerializerFactory;
>import org.apache.axis.encoding.ser.BeanSerializerFactory;
>import org.apache.axis.encoding.ser.BeanDeserializerFactory;
>import org.apache.axis.encoding.ser.EnumDeserializerFactory;
>import org.apache.axis.encoding.ser.EnumSerializerFactory;
>
>
>
>/**
>  * Holds AG support functionality.
>  *
>  * @version $Revision: #4 $
>  * @author Michael Binz
>  */
>public class AgSupportLib
>{
>     /**
>      * Logger used by this class
>      */
>     private static final Log _logger =
>         LogFactory.getLog( AgSupportLib.class );
>
>
>
>	/**
>	 * Generated classes from Axis.  This table is only necessary on
>Axis 1.1.
>      * Note that the classes commented with // enum ... require a special
>      * handling performed in registerAxisClassesInContext.  Keep them as
>      * as comments here so that they arent forgotten.
>      *
>      * TODO Remove as soon as Axis 1.2 is used.
>	 */
>	private static Class generatedAxisClasses[]={
>		AddressType.class,
>		AgencyInformationType.class,
>		CompanyType.class,
>		ErrorMessageType.class,
>		FunctionType.class,
>// enum GenderType.class,
>		LegalEventType.class,
>		MoneyType.class,
>		OptionalEntry.class,
>		PartyListType.class,
>		PartyMatrixType.class,
>		PartyType.class,
>		PersonType.class,
>		RatingType.class,
>		RequestType.class,
>		ResponseType.class,
>		ScoreType.class
>	};
>
>     private final static QName GenderTypeName =
>         new javax.xml.namespace.QName(
>             "http://ws.agw.guardean.net/schema",
>             getPlainClassName( GenderType.class ) );
>
>
>
>
>	/**
>	 * Register a set of generated classes from Axis in a Message
>Context
>	 *
>	 *@param pContext MessageContext where all the classes will be
>registered
>	 *@param pClassArray generated classes by Axis that will be register
>in the
>      *       context given as parameter
>	 */
>	private static void registerAxisClassesInContext(MessageContext
>pContext, Class pClassArray[]){
>		Class currentClass = null;
>		//TODO Is there a way to check dynamically the classes
>generated by Axis
>		//under the schema package??
>         //TODO Operation is not longer necessary on Axis 1.2.  No need to
>invest
>         // the time to make that finally cool on Axis 1.1 -- would be
>expensive.
>		if (pContext == null)
>			return;
>
>		if (pClassArray == null){
>			_logger.warn("No generated classes from Axis in
>system!.");
>			return;
>		}
>
>		TypeMapping typeMapping = pContext.getTypeMapping();
>
>		for(int i=0; i < pClassArray.length; i++){
>		    try{
>		        currentClass = pClassArray[i];
>		        // get TypeDesc from class
>		        Method gtd = currentClass.getMethod( "getTypeDesc",
>null );
>		        TypeDesc td = (TypeDesc)gtd.invoke( null, null );
>		        // register serializer and deserializer for this
>class
>		        typeMapping.register(
>                         currentClass,
>		                td.getXmlType(),
>
>BaseSerializerFactory.createFactory(BeanSerializerFactory.class,currentClass
>,td.getXmlType()),
>
>BaseDeserializerFactory.createFactory(BeanDeserializerFactory.class,currentC
>lass,td.getXmlType())
>             );
>			}catch(Exception e){
>				_logger.error("No Axis generated class ("+
>currentClass.getName()+")",e);
>             	throw new IllegalArgumentException(
>                 	"No Axis generated class: " + currentClass.getName()
>);
>			}
>		}
>
>		// Special handling for enumeration simple types.
>         // genderType
>         {
>             typeMapping.register(
>                 GenderType.class,
>                 GenderTypeName,
>                 EnumSerializerFactory.createFactory(
>                         EnumSerializerFactory.class,
>                         GenderType.class,
>                         GenderTypeName ),
>                 EnumDeserializerFactory.createFactory(
>                         EnumDeserializerFactory.class,
>                         GenderType.class,
>                         GenderTypeName ) );
>         }
>	}
>
>
>
>     /**
>      * <p>Transforms an instance of a type generated by Axis
>      * <code>WSDL2Java</code> into an XML representation, using only Axis
>APIs.
>      * <p>Note that this implementation only works on Axis data types 
>since
>      * only these are registered against the Axis runtime,</p>
>      *
>      * @param pO The object to be transformed.
>      * @param pQname The qualified name of the passed object.  Note that
>      *        passing the wrong value here does not result in an error, 
>but
>in
>      *        the generation of a wrong XML structure.  This can be 
>accessed
>
>      *        for a given type <i>Type</i> by the code
>      *        <code><i>Type</i>.getTypeDesc().getXmlType()</code>.
>      * @return An XML-stringified representation of the input object.
>      * @deprecated Use the single parameter version of this operation.
>QName
>      *             autodetection is save and simple.
>      */
>     private static String transformWsInstanceToXml( Object pO, QName 
>pQname
>)
>     {
>         // Since we are not in a message call context, we have to create a
>         // message context ourselves.
>         MessageContext mc = new MessageContext( new AxisClient() );
>         registerAxisClassesInContext( mc, generatedAxisClasses );
>         // This means that the XSI type attributes are not generated.
>         mc.setProperty( Call.SEND_TYPE_ATTR, "false" );
>
>         // This writer will ultimately receive the generated XML...
>         StringWriter result = new StringWriter();
>         // ...and is connected to the serialisation context.
>         SerializationContextImpl sci = new SerializationContextImpl(
>             result,
>             mc );
>         // Pretty print the result for convenience.
>         sci.setPretty(  true );
>
>         // MultiRef'ing means that when object graphs are serialized, the
>         // identity of objects is kept, i.e. first the first level objects
>are
>         // serialized with hrefs to the nested objects.  After that the
>nested
>         // objects are serialised and so on.
>         // This is not what we want.  We want instead an in-place 
>expansion
>of
>         // nested objects without the hassle of object decomposition, we
>have
>         // only plain vanilla data structures in the end.
>         sci.setDoMultiRefs( false );
>
>         try
>         {
>             // ...and perform the serialization.
>             sci.serialize(
>                     pQname,
>                     new AttributesImpl(),
>                     pO );
>         }
>         catch ( IOException e )
>         {
>             // This exception is triggered by the java.io.Writer in the
>             // SerialisationContext.  Since we use a StringWriter, we can
>             // guarantee that no IOExceptions will be thrown and safely
>             // ignore these.
>             _logger.warn( "java.io.StringWriter threw IOException.", e );
>         }
>
>         return result.toString();
>     }
>
>
>
>     /**
>      * Transforms the passed type into its XML representation.  The passed
>      * object must represent a type generated by the Axis WSDL compiler.
>      *
>      * @param pO The object to be transformed.
>      * @return The passed object's XML representation in string format.
>      * @throws IllegalArgumentException If the passed object is not an
>instance
>      *         of an Axis-generated type.
>      */
>     public static String axisToXml( Object pO )
>     {
>         Class oClass = pO.getClass();
>
>         try
>         {
>             // Get the type description via the static method.
>             Method gtd = oClass.getMethod( "getTypeDesc", null );
>             TypeDesc td = (TypeDesc)gtd.invoke( null, null );
>             // From the type description get the QName.
>             return transformWsInstanceToXml( pO, td.getXmlType() );
>         }
>         catch ( Exception e )
>         {
>             // Check whether this is one of the non-complex types in the
>             // package.  In this case we synthesize a QName. Holy cow,
>looking
>             // forward to Axis 1.2
>             return transformWsInstanceToXml(
>                     pO,
>                     new javax.xml.namespace.QName(
>                             "http://ws.agw.guardean.net/schema",
>                             getPlainClassName( pO.getClass() ) ) );
>         }
>     }
>
>
>
>     /**
>      * Transforms the passed type into its XML representation.  The passed
>      * object must represent a type generated by the Axis WSDL compiler.
>      *
>      * @param pO The object to be transformed.
>      * @return The passed object's XML representation in string format.
>      * @deprecated Use axisToXml() instead.
>      * @throws IllegalArgumentException If the passed object is not an
>instance
>      *         of an Axis-generated type.
>      */
>     public static String transformWsInstanceToXml( Object pO )
>     {
>         return axisToXml( pO );
>     }
>
>
>
>     /**
>      * Convert an XML structure created from an Axis-generated class back
>into
>      * an object representation.
>	 *
>      * @param xml The XML structure.  Generated by
>      *        <code>axisToXml( Object )</code>.
>      * @param pQname The qualified name of the target type.
>      * @return An instance of the Axis generated class.
>      * @see AgSupportLib#axisToXml(Object)
>      */
>     public static Object xmlToAxis( String xml, QName pQname )
>     {
>         // TODO would be cool to dynamically detect the target qname.  
>This
>         // could be done by looking at the first element's name in the
>inbound
>         // XML data.
>
>         try
>         {
>     		// Wrap the InputStream up into a SOAP Body and Envelope
>since the parser
>		    // expects a SOAP Envelope
>     		SOAPEnvelope env1 = new SOAPEnvelope();
>     		env1.addBodyElement(
>                     new SOAPBodyElement(
>                             new ByteArrayInputStream(xml.getBytes())));
>
>             // Since we are not in a message call context, we have to 
>create
>a
>             // message context ourselves.
>             MessageContext mc = new MessageContext( new AxisClient() );
>             // TODO: This following line manually registers the generated
>type
>             // mappings.  This has to be removed as soon as Axis 1.2 is
>used.
>
>registerAxisClassesInContext(mc,generatedAxisClasses);
>
>             InputSource is =
>                 new InputSource( new StringReader( env1.toString() ) );
>
>             // ...and is connected to the serialisation context.
>             DeserializationContextImpl sci = new 
>DeserializationContextImpl(
>                     is, mc, org.apache.axis.Message.REQUEST );
>             sci.parse();
>
>             SOAPEnvelope env2 = sci.getEnvelope();
>             RPCElement rpcElem = (RPCElement) env2.getFirstBody();
>
>             // On Axis 1.2 use the getValueAsType( qname, class ) in the
>next
>             // line and not the single arg version.
>             //return rpcElem.getValueAsType(qname, clazz);
>             return rpcElem.getValueAsType( pQname ); // Axis 1.1 code.
>         }
>         catch ( Exception e )
>         {
>             _logger.debug( "deserialisation problem.", e );
>             throw new IllegalArgumentException(
>               e.getMessage() );
>         }
>     }
>
>
>
>     /**
>      *
>      * @param pclass
>      * @return
>      */
>     public static String getPlainClassName( Class pclass )
>     {
>         String fullyQualified = pclass.getName();
>         int lastDot = fullyQualified.lastIndexOf( '.' );
>         if ( lastDot == -1 )
>             return fullyQualified;
>
>         return fullyQualified.substring( lastDot+1 );
>     }
>
>
>
>     /**
>      * Test code.
>      *
>      * @param argv
>      */
>     public static void main( String[] argv )
>     {
>         LegalEventType o = new LegalEventType();
>
>         o.setDate( new Date() );
>         o.setDescription( "This is a test for legal event serialisation." 
>);
>         o.setHasExpired( Boolean.TRUE );
>
>		System.out.println( "Serialized Object. Description: " +
>o.getDescription() );
>		System.out.println( "Serialized Object. hasExpired: " +
>o.getHasExpired() );
>		System.out.println( "Serialized Object: Date: " +
>o.getDate() );
>
>         String intermediateString = transformWsInstanceToXml( o );
>
>         Object deserialised = xmlToAxis(
>             intermediateString,
>             LegalEventType.getTypeDesc().getXmlType() );
>
>		LegalEventType t = (LegalEventType) deserialised;
>
>		System.out.println( "Deserialized Object. Description: " +
>o.getDescription() );
>		System.out.println( "Deserialized Object. hasExpired: " +
>o.getHasExpired() );
>		System.out.println( "Deserialized Object: Date: " +
>o.getDate() );
>         //System.err.println( "" + deserialised );
>
>         GenderType gender = GenderType.FEMALE;
>         intermediateString = transformWsInstanceToXml( gender );
>         System.err.println( intermediateString );
>         deserialised = xmlToAxis( intermediateString, GenderTypeName );
>         System.err.println( deserialised.toString() );
>         Gender g = AgTransformer.transform( (GenderType)deserialised );
>         System.err.println( "Gender is: " + g );
>     }
>}
>=== END ===
>
>
> > -----Original Message-----
> > From: tom ONeill [mailto:beagleboythefirst@hotmail.com]
> > Sent: Monday, September 27, 2004 10:44 AM
> > To: axis-user@ws.apache.org
> > Subject: Deserializing XML w/o using client stubs
> >
> >
> > Hi all,
> >
> > I have used the WSDL2Java utility to generate client stubs to
> > invoke an
> > external partners web service. My component receives a large
> > XML string
> > which represents the datatype which will be passed as a
> > parameter to the web
> > service call. Thus I need a way of deserializing this XML
> > string into the
> > appropriate Java type (as oppossed to creating the Java type
> > within my code
> > and populating its member variables). I would expect to be
> > able create some
> > kind of Document object from my XML string and then use an Axis
> > derserializer to return the appropriate Java type. However if
> > is not clear
> > from the Axis API how I might do this.
> >
> > Any help appreciated.
> >
> > Regards,
> > Tom
> >
> > _________________________________________________________________
> > MSN 8 helps eliminate e-mail viruses. Get 2 months FREE*.
> > http://join.msn.com/?page=features/virus
> >
>
>--
>GMX ProMail mit bestem Virenschutz http://www.gmx.net/de/go/mail
>+++ Empfehlung der Redaktion +++ Internet Professionell 10/04 +++
>

_________________________________________________________________
Get ready for school! Find articles, homework help and more in the Back to 
School Guide! http://special.msn.com/network/04backtoschool.armx


Mime
View raw message