JAXB Eclipse MOXy Nullable值并仅检索Map中的指定键

时间:2013-04-10 16:19:36

标签: jaxb eclipselink jaxb2 moxy

我还有另一个棘手的问题:

E.g. Person Class has: --String firstName --String lastName --Map stringMap

   Person person = new Person ();
   person.setFirstName("FirstName");
   person.setLastName("LastName");
   Map<String,String> stringMap = new HashMap<String,String>();
   stringMap.put("IwantThisKeyInXml","IwantThisValueInXml");
   stringMap.put("IDONTwantThisKeyInXml","IDONTwantThisValueInXml");


   InputStream iStream1 = classLoader.getResourceAsStream("person-binding.xml");
   List<Object> fileList = new ArrayList<Object>();
            fileList.add(iStream1);
   Map<String, Object> properties = new HashMap<String,Object>();               

   properties.put(JAXBContextProperties.OXM_METADATA_SOURCE,  fileList);
   JAXBContext ctx = JAXBContext.newInstance(new Class[] { GaDictionary.class, Person.class }, properties);

   Marshaller marshaller = ctx.createMarshaller();
   marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

   Writer output = new StringWriter();
   marshaller.marshal(person, output);
   System.out.println(output);

person-binding.xml在

之下
   <?xml version="1.0"?>
   <xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="my.test.model"  xml-mapping-metadata-complete="true">
    <xml-schema
        element-form-default="QUALIFIED"/>
    <java-types>
        <java-type name="Person"  xml-accessor-type="NONE">
            <xml-root-element/>
            <xml-type prop-order="firstName lastName"/>
            <java-attributes>
                <xml-element java-attribute="firstName" name="first-name"/>
                <xml-element java-attribute="lastName" name="last-name"/>
                <xml-element java-attribute="stringMap" name="string-map"/>
            </java-attributes>
        </java-type>
      </java-types>
    </xml-bindings>

因此,结果的定义是:

   <?xml version="1.0" encoding="UTF-8"?>
   <person>
   <first-name>FirstName</first-name>
   <last-name>LastName</last-name>
   <string-map>
      <entry>
         <key>IwantThisKeyInXml</key>
         <value>IwantThisKeyInXml</value>
      </entry>
      <entry>
         <key>IDONTwantThisKeyInXml</key>
         <value>IDONTwantThisKeyInXml</value>
      </entry>
   </string-map>
   </person>

如何在stringMap上排除该条目?我试过虚拟访问方法,但也许我无法正确配置它?!编组后我应该删除该值吗?这可能是一种聪明且可维护的方式吗?

最后一个问题是我是否拥有属性的空值。如何配置person-binding-xml文件(oxm.file)以使相对xml标记为空?

我可以更改模型类,但我更喜欢在可能的情况下不添加任何代码行。 (这就是我填充xml文件的原因)

所以我想获得的结果是:

 <?xml version="1.0" encoding="UTF-8"?>
   <person>
     <first-name>FirstName</first-name>
     <last-name>LastName</last-name>
     <string-map>
       <entry>
         <key>IwantThisKeyInXml</key>
         <value>IwantThisKeyInXml</value>
       </entry>
      </string-map>
  </person>

关于第二个相关问题: 我试过nillable =“true”但它不起作用! 所以对于istance如果我对stringMap或firstName或其他东西有空值我会分别得到  并用任何身体标记。

或者我想获得的另一种方式是:

 <?xml version="1.0" encoding="UTF-8"?>
   <person>
     <first-name>FirstName</first-name>
     <last-name>LastName</last-name>
     <string-map>
       <entry>
         <key>IwantThisKeyInXml</key>
         <value>IwantThisKeyInXml</value>
       </entry>
       <entry><!-- I have the entry but I have an empty value-->
         <key>KEY</key>
         <value></value>
       </entry>
      </string-map>
  </person>

感谢所有

3 个答案:

答案 0 :(得分:4)

在您的解决方案中,null-policy是正确的想法,但它需要在StringEntryType的value属性上,而不是在整个地图上。所以你的绑定文件应该包含这样的内容:

 <java-type name="StringEntryType">
        <java-attributes>
            <xml-element java-attribute="value" name="value">
                <xml-null-policy null-representation-for-xml="EMPTY_NODE"/>
            </xml-element>
        </java-attributes>
    </java-type>

你的解决方案看起来不错,但我想我也会发布一个替代解决方案,它使用你可能更喜欢的MOXy的只读和只写属性。在此示例中,变量myMap将在unmarshal期间设置,但在编组期间,将调用从getModifiedMap方法返回的Map。在getModifiedMap中,我们还使用空字符串替换空值,以便对空标记进行编组。

public class Root {

    public Map<String, String> myMap = new HashMap<String, String>();

    public Map<String, String> getModifiedMap(){
         Map modifiedMap = new HashMap<String, String>();       
         Set<Entry<String, String>> entries = myMap.entrySet();
         Iterator<Entry<String, String>> iter = entries.iterator();
         while(iter.hasNext()){
             Entry<String, String> nextEntry = iter.next();
             String nextKey = nextEntry.getKey();
             if(!nextKey.equals("omitthiskey")){
                 String nextValue = nextEntry.getValue();
                 if(nextValue == null){
                     nextValue ="";
                 }               
                 modifiedMap.put(nextKey, nextValue);
             }
         }
         return modifiedMap;
    }

    public void setModifiedMap(Map<String, String> newMap){
        //this method shouldn't get hit but needs to be present 
    }
}

并且相应的绑定文件将包含以下内容:

<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="test2" >
    <xml-schema element-form-default="QUALIFIED"/>  
    <java-types>
    <java-type name="Root"  xml-accessor-type="NONE">
        <xml-root-element/>
        <java-attributes>
            <xml-element java-attribute="myMap" name="myMap" read-only="true" />
            <xml-element java-attribute="modifiedMap" name="myMap" write-only="true"/>                      
        </java-attributes>
    </java-type>                    
    </java-types>
</xml-bindings>

答案 1 :(得分:1)

如果您想阻止某些Map条目被编组为XML,您可以提供一个XmlAdapter,它将在编组时删除任何不需要的条目:

import java.util.Map;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public final class MyAdapter extends XmlAdapter<Map<String, String>, Map<String, String>> {

    private final String OMIT = "IDONTwantThisKeyInXml";

    @Override
    public Map<String, String> unmarshal(Map<String, String> arg0) throws Exception {
        return arg0;
    }

    @Override
    public Map<String, String> marshal(Map<String, String> arg0) throws Exception {
        if (arg0 != null) {
            arg0.remove(OMIT);
        }
        return arg0;
    }

}

我不确定我理解你的第二个问题,你能解释一下你想看到的行为吗?

希望这有帮助,

瑞克

答案 2 :(得分:0)

我找到了正确的解决方案:

        import java.util.HashMap;
        import java.util.Map;
        import java.util.Map.Entry;

        import javax.xml.bind.annotation.adapters.XmlAdapter;

        public final class StringMapAdapter extends XmlAdapter<StringAdapterMap, Map<String, String>> {

            private final String OMIT = "birthPlaceString";

            @Override
            public Map<String, String> unmarshal(StringAdapterMap v) throws Exception {
                 HashMap<String, String> hashMap = new HashMap<String, String>();
                 System.out.println("unmarshal"); 
                 for(StringEntryType myEntryType : v.entry) {
                     hashMap.put(myEntryType.key, myEntryType.value);
                  }
                  return hashMap;
            }

            @Override
            public StringAdapterMap marshal(Map<String, String> v) throws Exception {
                StringAdapterMap myMapType = new StringAdapterMap();
              for(Entry<String, String> entry : v.entrySet()) {
                  StringEntryType EntryType = new StringEntryType();
                   EntryType.key= entry.getKey();
                   EntryType.value = entry.getValue();
                   if (!OMIT.equals(EntryType.key))
                       myMapType.entry.add(EntryType);
              }
              return myMapType;

            }

StringAdapterMap类:

        import java.util.ArrayList;
        import java.util.List;

        public class StringAdapterMap {
             public List<StringEntryType> entry = new ArrayList<StringEntryType>();

        }

StringEntryType类:

        public class StringEntryType {

               public String key;

               public String value;

        }
在oxm.file中

记得配置适配器

     <xml-element java-attribute="stringMap" name="string-map" >
      <xml-java-type-adapter value="it.cineca.jaxb.adapter.StringMapAdapter" />    
     </xml-element>