【问题标题】:JAXB Eclipse MOXy Nullable value and retrieve only a specified key in a MapJAXB Eclipse MOXy Nullable 值并仅检索 Map 中的指定键
【发布时间】:2013-04-10 16:19:35
【问题描述】:

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

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" 但它不起作用! 所以举个例子,如果我有一个 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>

谢谢大家

【问题讨论】:

    标签: jaxb eclipselink jaxb2 moxy


    【解决方案1】:

    在您的解决方案中,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 将在解组期间设置,但在编组期间将从 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>
    

    【讨论】:

    • 感谢您的贡献!
    • 我的模型中有很多 Map 属性,我不需要为每个地图使用适配器。当地图为空时,我如何获得 ?我试过&lt;xml-element java-attribute="clobMap" &gt; &lt;xml-null-policy null-representation-for-xml="EMPTY_NODE"/&gt; &lt;/xml-element&gt;,但它不起作用!我不得不说 StringEntryType 它只是我为适配器创建的 Map 的类型。如果我有 Map 或 Map 我应该为每个 Map 声明一个适配器吗?这不是一个糟糕的解决方案吗?
    【解决方案2】:

    如果您想防止某些 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;
        }
    
    }
    

    不确定我是否理解您的第二个问题,您能否详细解释一下您希望看到的行为?

    希望这会有所帮助,

    瑞克

    【讨论】:

    • 实际上,回顾这个​​例子,绑定文件中没有指定适配器(我对你的其他帖子感到困惑)。您需要对 person-bindings.xml 进行以下更改:&lt;xml-element java-attribute="stringMap" name="string-map"&gt;&lt;xml-java-type-adapter value="com.yourpackage.MyAdapter" /&gt;&lt;/xml-element&gt;
    • 我很困惑,因为您的另一个问题指定了 xml-java-type-adapter 但这个没有。那么,您在绑定中指定了适配器,您的 StringMapAdapter 类实际上是否受到元帅的打击?
    • 你能在你的适配器中放一个断点,并确认你的 StringMapAdapter 类实际上被 marshal 命中了吗?它一定不能通过代码来删除不需要的元素。
    • 我删除了评论,这样其他用户可以阅读更少的内容,而只有解决方案。我找到了上面的解决方案。不幸的是,REMOVE 会导致类似 {ORCID=0000-0001-8671-2284, researcherId=C-3388-2013} 的输出
    • 我的模型中有很多 Map 属性,我不需要为每个地图使用适配器。当地图为空时,我如何获得 ?我尝试使用 但它不起作用!我不得不说 StringEntryType 它只是我为适配器创建的 Map 的类型。如果我有 Map 或 Map 我应该为每个 Map 声明一个适配器吗?这不是一个糟糕的解决方案吗?
    【解决方案3】:

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

            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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-15
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 2019-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多