简体   繁体   中英

How to map simple Java class's field names into sequence of name-value pairs

I have a very simple class that I want to transmit as XML. The accepted XML format is a list of fields made of name attribute and sequence of string values. Can I annotate my class so that I can:

  1. Use class name as attribute "type" of xml entity
  2. Use class fields names as attribute "name" in xml sequence of Fields ?

What would be the recommended way? The example class in question:

class MyEntityType {
    public List<String> myField1; // = {"A", "B"}
    public List<String> myField2; // = {"C", "D"}
}

in xml format:

<Entity type="MyEntityType">
    <Fields>
        <Field name="myField1">
            <Value>A</Value>
            <Value>B</Value
        </Field>
        <Field name="myField2">
            <Value>C</Value>
            <Value>D</Value>
        </Field>
    </Fields>
</Entity>

What I would like to avoid is having to declare a Field class, and put a list of them in my object, because I want to enforce a particular set of required fields.

class MyEntityType {
    public static class Field {
        String name;
        String values
    }
    public List<Fields> fields;
}

For completeness these are supported schemas:

<xs:complexType name="EntityComplexType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:sequence>
    <xs:element name="Fields" type="FieldsComplexType" />
  </xs:sequence>
  <xs:attribute name="Type" type="xs:string" use="required" />
</xs:complexType>

<xs:complexType name="FieldsComplexType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:sequence>
    <xs:element name="Field" type="FieldComplexType" maxOccurs="unbounded" />
  </xs:sequence>
</xs:complexType>

<xs:complexType name="FieldComplexType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:sequence>
    <xs:element name="Value" minOccurs="0" maxOccurs="unbounded">
      <xs:complexType>
        <xs:simpleContent>
          <xs:extension base="xs:string">
            <xs:attribute name="Alias" type="xs:string" use="optional" />
            <xs:attribute name="ReferenceValue" type="xs:string" use="optional" />
          </xs:extension>
        </xs:simpleContent>
      </xs:complexType>
    </xs:element>
  </xs:sequence>
  <xs:attribute name="Name" use="required" />
</xs:complexType>

I suppose that you realize that what you want is a significant deviation from XML's standard procedure, ignoring the concepts underlying the design of this data format, and the Java Architecture for XML Binding as well. Thus, class fields are meant to be represented by element names. Also, using an XML structure that does not reflect the structure of the data (class MyEntityType) or, vice versa, using a class that does not correspond to the structure of the data creates a gap that no out-of-the-box tool can handle. There are neither annotations nor external bindings to achieve this completely different structure.

There is, of course, the JAXB feature of adapter, which helps to replace one Java type by another, but here one has to replace the entire Java structure before it can be marshalled into XML.

Your XML schema (with a small correction) generates the required Java classes EntityComplexType, FieldsComplexType and FieldComplexType (which I don't paste here).

A Java class EntityAdapter can be written in the spirit of an adapter:

public class EntityAdapter {
    public MyEntityType unmarshal(EntityComplexType v){
        // ...
        return new MyEntityType();
    }
    public EntityComplexType marshal(MyEntityType v){
        EntityComplexType ect = new EntityComplexType();
        ect.setType( v.getClass().getSimpleName() );
        FieldsComplexType fct = new FieldsComplexType();
        ect.setFields( fct );
        FieldComplexType field1 = new FieldComplexType();
        fct.getField().add( field1 );
        field1.setName( "myField1" );
        for( String s: v.getMyField1() ){
            field1.getValue().add( s );
        }
        FieldComplexType field2 = new FieldComplexType();
        fct.getField().add( field2 );
        field2.setName( "myField2" );
        for( String s: v.getMyField2() ){
            field2.getValue().add( s );
        }
        return ect;
    }
}

And marshalling proceeds as usual, with the addition of transforming the MyEntityType object to an EntityComplexType object:

MyEntityType met = ...;
EntityAdapter adapter = new EntityAdapter();
EntityComplexType ect = adapter.marshal( met );
ObjectFactory of = new ObjectFactory();
JAXBElement<EntityComplexType> jbe = of.createEntityComplexType( ect );
JAXBContext jc = JAXBContext.newInstance( PACKAGE );
Marshaller m = jc.createMarshaller();
m.marshal( jbe, ... );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM