JAXB编组地图列表列表

时间:2012-07-31 16:28:47

标签: java jaxb marshalling

民间,

我是使用JAXB进行编组和解组对象的新手。

我正在尝试编组一个最好被称为地图列表列表的对象。

我想要达到的最终结果如下:

<parametricSearchResult>
   <allFilters>
      <name>custom_year</name>
      <name>abcd</name>
   </allFilters>
   <allFields>
      <field>
         <name>custom_year</name>
         <value count="10">2012</value>
         <value count="8">2011</value>
      </field>
      <field>
         <name>abcd</name>
         <value count="8">2011</value>
      </field>
   </allFields>
</parametricSearchResult>

使用我编写的代码,我将其作为输出

<parametricSearchResult>
    <allFilters>
        <name>custom_year</name>
        <name>abcd</name>
    </allFilters>
    <allFields>
        <allFilters>
            <mName>test</mName>
            <field>
                <value count="10">
                    <mValue>2012</mValue>
                </value>
                <value count="8">
                    <mValue>2011</mValue>
                </value>
            </field>
            <name>test</name>
        </allFilters>
        <allFilters>
            <mName>test</mName>
            <field>
                <value count="4">
                    <mValue>2011</mValue>
                </value>
            </field>
            <name>test</name>
        </allFilters>
    </allFields>
</parametricSearchResult>

我的代码如下:

ParametricSearchResult

@XmlRootElement(name = "parametricSearchResult")
public class ParametricSearchResult {

    private final List<String> mFilterFields = new ArrayList<String>();

    private final List<Map<String, Integer>> mFiltersToCountsMap = new ArrayList<Map<String, Integer>>();

    public void setFilterFields(List<String> fields) {
        mFilterFields.addAll(fields);
    }

    @XmlElementWrapper(name = "allFilters")
    @XmlElement(name = "name")
    public List<String> getFilterFields() {
        return mFilterFields;
    }

    @XmlElement(name = "allFields")
    @XmlJavaTypeAdapter(JAXBParametricSearchResultSerializer.class)
    public List<Map<String, Integer>> getValuesAndCounts() {
        return mFiltersToCountsMap;
    }

    public void addFilterFieldsAndCounts(final String field, final String filterValue, final Integer count) {
        final int index = mFilterFields.indexOf(field.toLowerCase());
        if (index == -1) {
            mFilterFields.add(field.toLowerCase());
            HashMap<String, Integer> mapValuesToCounts = new HashMap<String, Integer>();
            mapValuesToCounts.put(filterValue.toLowerCase(), Integer.valueOf(count));
            mFiltersToCountsMap.add(mapValuesToCounts);
        } else {
            Map<String, Integer> mapValuesToCounts = mFiltersToCountsMap.get(index);
            mapValuesToCounts.put(filterValue.toLowerCase(), Integer.valueOf(count));
        }
    }

    public Map<String, Integer> getFilterValueToCountMap(String filterName) {
        final int index = mFilterFields.indexOf(filterName.toLowerCase());
        if (index == -1) {
            return new HashMap<String, Integer>();
        } else {
            return mFiltersToCountsMap.get(index);
        }
    }   
}

ParametricSearchResultType

public class ParametricSearchResultType {

    private final List<ParametricFilterType> allFilters = new ArrayList<ParametricFilterType>();

    @XmlElement
    public List<ParametricFilterType> getFilters() {
        return allFilters;
    }

    public void setFilter(final ParametricFilterType data) {
        allFilters.add(data);
    }
}

ParametricFilterType

public class ParametricFilterType {

    private String mName = "";

    private final List<ParametricMapEntryType> mFilterAllEntries = new ArrayList<ParametricMapEntryType>();

    @XmlElement(name = "name")
    public String getName() {
        return mName;
    }

    public void setName(final String data) {
        mName = data;
    }

    public void setAllFilters(final ParametricMapEntryType data) {
        mFilterAllEntries.add(data);
    }

    @XmlElementWrapper(name = "field")
    @XmlElement(name = "value")
    public final List<ParametricMapEntryType> getAllFilterEntries() {
        return mFilterAllEntries;
    }
}

ParametricMapEntryType

public class ParametricMapEntryType {

    @XmlValue
    public String mValue;

    @XmlAttribute(name = "count")
    public Integer mCount;

}

JAXBParametricSearchResultSerializer

public class JAXBParametricSearchResultSerializer extends XmlAdapter<ParametricSearchResultType, List<Map<String, Integer>>> {

    @Override
    public ParametricSearchResultType marshal(final List<Map<String, Integer>> data) throws Exception {
        ParametricSearchResultType result = new ParametricSearchResultType();
        for (Map<String, Integer> aMap : data) {
            ParametricFilterType filters = new ParametricFilterType();
            filters.mName = "test";
            for (Map.Entry<String, Integer> anEntry : aMap.entrySet()) {
                ParametricMapEntryType entry = new ParametricMapEntryType();
                entry.mValue = anEntry.getKey();
                entry.mCount = anEntry.getValue();
                filters.mFilterAllEntries.add(entry);
            }
            result.allFilters.add(filters);
        }
        return result;
    }

    @Override
    public List<Map<String, Integer>> unmarshal(final ParametricSearchResultType data) throws Exception {
        return null;
    }

}

ParametricSearchResultTester

public class ParametricSearchResultTester {

    ParametricSearchResult mResult;

    @Before
    public void setUp() throws Throwable {

        mResult = new ParametricSearchResult();
        mResult.addFilterFieldsAndCounts("CUSTOM_YEAR", "2012", 10);
        mResult.addFilterFieldsAndCounts("CUSTOM_YEAR", "2011", 8);
        mResult.addFilterFieldsAndCounts("ABCD", "2011", 4);
    }

    @After
    public void tearDown() throws Throwable {
        mResult = null;
    }

    @Test
    public void testThatMarshallingWorks() throws Throwable {
        JAXBContext context = JAXBContext.newInstance(ParametricSearchResult.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(mResult, System.out);
    }
}

在阅读了更多文档后对代码进行了一些更改,并在进行了这些更改之后,我最终将此作为输出

<parametricSearchResult>
    <allFilters>
        <name>custom_year</name>
        <name>abcd</name>
    </allFilters>
    <allFields>
        <filters>
            <field>
                <value count="10">2012</value>
                <value count="8">2011</value>
            </field>
            <name>test</name>
        </filters>
        <filters>
            <field>
                <value count="4">2011</value>
            </field>
            <name>test</name>
        </filters>
    </allFields>
</parametricSearchResult>

几乎在那里,但仍需要更多的清理和重新排列元素。不知道还有什么可以做的。

3 个答案:

答案 0 :(得分:0)

对不起如果不深入了解您的要求,业务等,我无法给出您期望的答案。

这是我的伪尝试。

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
@XmlType(propOrder = {"filterNames", "fields"})
public class ParametricSearchResult {


    @XmlAccessorType(XmlAccessType.NONE)
    @XmlType(propOrder = {"name", "values"})
    public static class Field {


        public static Field newInstance(final String name,
                                        final Value... values) {

            final Field instance = new Field();

            instance.setName(name);

            for (Value value : values) {
                instance.getValues().add(value);
            }

            return instance;
        }


        @XmlAccessorType(XmlAccessType.NONE)
        public static class Value {


            public static Value newInstance(final int count,
                                            final String value) {

                final Value instance = new Value();

                instance.setCount(count);
                instance.setValue(value);

                return instance;
            }


            public int getCount() {
                return count;
            }


            public void setCount(final int count) {
                this.count = count;
            }


            public String getValue() {
                return value;
            }


            public void setValue(final String value) {
                this.value = value;
            }


            @XmlAttribute(required = true)
            private int count;


            @XmlValue
            private String value;


        }


        public String getName() {
            return name;
        }


        public void setName(final String name) {
            this.name = name;
        }


        public Collection<Value> getValues() {

            if (values == null) {
                values = new ArrayList<Value>();
            }

            return values;
        }


        @XmlElement(required = true)
        private String name;


        @XmlElement(name = "value")
        private Collection<Value> values;


    }


    public static void main(final String[] args)
        throws JAXBException, IOException {

        final ParametricSearchResult result = new ParametricSearchResult();

        result.getFilterNames().add("custom_year");
        result.getFilterNames().add("abcd");

        result.getFields().add(
            Field.newInstance(
            "custom_year",
            Value.newInstance(10, "2012"),
            Value.newInstance(8, "2011")));

        result.getFields().add(
            Field.newInstance(
            "abcd",
            Value.newInstance(8, "2011")));

        final JAXBContext context =
            JAXBContext.newInstance(ParametricSearchResult.class);

        final Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        marshaller.marshal(result, System.out);

        System.out.println("-------------------------------------------------");

        context.generateSchema(new SchemaOutputResolver() {


            @Override
            public Result createOutput(final String namespaceUri,
                                       final String suggestedFileName)
                throws IOException {

                return new StreamResult(System.out) {


                    @Override
                    public String getSystemId() {
                        return "noid";
                    }


                };
            }


        });
    }


    public Collection<String> getFilterNames() {

        if (filterNames == null) {
            filterNames = new ArrayList<String>();
        }

        return filterNames;
    }


    public Collection<Field> getFields() {

        if (fields == null) {
            fields = new ArrayList<Field>();
        }

        return fields;
    }


    @XmlElement(name = "name")
    @XmlElementWrapper(name = "allFilters", nillable = true, required = true)
    private Collection<String> filterNames;


    @XmlElement(name = "field")
    @XmlElementWrapper(name = "allFields", nillable = true, required = true)
    private Collection<Field> fields;


}

打印

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<parametricSearchResult>
    <allFilters>
        <name>custom_year</name>
        <name>abcd</name>
    </allFilters>
    <allFields>
        <field>
            <name>custom_year</name>
            <value count="10">2012</value>
            <value count="8">2011</value>
        </field>
        <field>
            <name>abcd</name>
            <value count="8">2011</value>
        </field>
    </allFields>
</parametricSearchResult>

这里是XML Schema。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="parametricSearchResult" type="parametricSearchResult"/>

  <xs:complexType name="parametricSearchResult">
    <xs:sequence>
      <xs:element name="allFilters" nillable="true">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="allFields" nillable="true">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="field" type="field" minOccurs="0" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="field">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="value" type="value" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="value">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="count" type="xs:int" use="required"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>

答案 1 :(得分:0)

JAXB不擅长处理Map,因此需要适配器。基本上,大多数地图适配器将地图转换为条目列表。一旦你有一个好的适配器,你可以有一个扩展List&gt;的对象,然后该对象可以包含在List本身中。

您可能能够让您的XML看起来与您想要的更加简洁,但是当用于实例化泛型的类型不同时,此解决方案将不可移植。

答案 2 :(得分:0)

民间,

经过一段时间的研究,我改变了我试图创造不同物体的方式。

这就是我为解决问题而采取的措施。我创建了三个新类,如下所示。在做了一些阅读之后,这就是我想出来的。

<强> ParametricSingleFilterMapEntry

public class ParametricSingleFilterMapEntry {

    private String mValue;

    private Integer mCount;

    public void setValue(final String data) {
        mValue = data;
    }

    @XmlValue
    public String getValue() {
        return mValue;
    }

    public void setCount(final Integer count) {
        mCount = count;
    }

    @XmlAttribute(name = "count")
    public Integer getCount() {
        return mCount;
    }
}

包含ParametricSingleFilterMapEntry

列表的下一个类

<强> ParametricSingleFilterAllEntries

@XmlType(propOrder = {"fieldName", "allEntriesForSingleField"})
public class ParametricSingleFilterAllEntries {

    private String mFilterField;

    private final List<ParametricSingleFilterMapEntry> mAllEntriesForSingleField = new ArrayList<ParametricSingleFilterMapEntry>();

    public void setField(final String name) {
        mFilterField = name;
    }

    @XmlElement(name = "name")
    public String getFieldName() {
       return mFilterField;
    }

    public void setAllMapEntries(final List<ParametricSingleFilterMapEntry> data) {
        mAllEntriesForSingleField.addAll(data);
    }

    public void setAMapEntry(final ParametricSingleFilterMapEntry entry) {
        mAllEntriesForSingleField.add(entry);
    }

    @XmlElement(name = "value")
    public List<ParametricSingleFilterMapEntry> getAllEntriesForSingleField() {
        return mAllEntriesForSingleField;
    }    
}

最后一节很好地将上述两个类联系起来

<强> ParametricSearchResult

@XmlRootElement(name = "parametricSearchResult")
public class ParametricSearchResult {

    private final List<ParametricSingleFilterAllEntries> mAllFilterEntries = new ArrayList<ParametricSingleFilterAllEntries>();

    @XmlElementWrapper(name = "allFields")
    @XmlElement(name = "field")
    public List<ParametricSingleFilterAllEntries> getAllFilterEntries() {
        return mAllFilterEntries;
    }

    public void addEntry(final ParametricSingleFilterAllEntries entry) {
        mAllFilterEntries.add(entry);
    }

    public void addEntries(final List<ParametricSingleFilterAllEntries> entries) {
        mAllFilterEntries.addAll(entries);
    }

    public void addEntry(final String filterName, final String filterValue, final Integer count) {
        if (StringUtils.isNotBlank(filterName)) {
            ParametricSingleFilterMapEntry newMapEntry = new ParametricSingleFilterMapEntry();
            newMapEntry.setValue(filterValue);
            newMapEntry.setCount(count);
            if (mAllFilterEntries.isEmpty()) {
                ParametricSingleFilterAllEntries newFilterEntry = new ParametricSingleFilterAllEntries();
                newFilterEntry.setField(filterName);
                newFilterEntry.setAMapEntry(newMapEntry);                
                addEntry(newFilterEntry);
                return;
            } else {
                ParametricSingleFilterAllEntries newFilterEntry = new ParametricSingleFilterAllEntries();
                for (ParametricSingleFilterAllEntries entry : mAllFilterEntries) {
                    if (StringUtils.isNotBlank(entry.getFieldName())) {
                        if (entry.getFieldName().equalsIgnoreCase(filterName)) {
                            entry.setAMapEntr(newMapEntry);                            
                            return;
                        } else {
                            continue;
                        }
                    }
                }
                newFilterEntry.setField(filterName);
                newFilterEntry.setAMapEntry(newMapEntry);                        
                addEntry(newFilterEntry);
            }
        }
    }
}

希望这种方法可以帮助其他可能遇到类似问题的人。