3

皆さん、

オブジェクトのマーシャリングとアンマーシャリングに 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>

ほぼ完了ですが、要素のクリーンアップと再配置が必要です。ここで他に何をすべきかわからない。

4

3 に答える 3

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スキーマがあります。

<?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>
于 2012-08-01T15:02:04.887 に答える
0

JAXB は Map を扱うのが得意ではないため、アダプターが必要です。基本的に、ほとんどのマップ アダプターは、マップをエントリのリストに変換します。優れたアダプターがあれば、List> を拡張するオブジェクトを作成でき、そのオブジェクトを List 自体に含めることができます。

おそらく、XML の外観を希望どおりに調整することはできますが、ジェネリックのインスタンス化に使用される型が異なる場合、このソリューションは移植性がありません。

于 2012-08-08T23:05:03.450 に答える
0

皆さん、

これについてしばらく考えた後、さまざまなオブジェクトを作成しようとしていた方法を作り直しました。

これが私の悩みを解決するために私がしたことです。以下に示すように、3つの新しいクラスを作成しました。もう少し読んだ後、これが私が思いついたものです。

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;
    }    
}

そして、上記の 2 つのクラスをうまく結び付ける最後のクラス

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);
            }
        }
    }
}

このアプローチが、同様の問題に直面する可能性のある他の誰かに役立つことを願っています。

于 2012-08-29T15:30:34.060 に答える