Search code examples
jaxbeclipselinkjaxb2moxy

JAXB Eclipse MOXy Nullable value and retrieve only a specified key in a Map


I have another more tricky question:

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 is below

   <?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>

So accordingly the definition the result is:

   <?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>

How Could I exclude that entry on the stringMap? I tried with virtual access method but maybe I wasn't able to configure it properly?! Should I remove that value after marshaling? Which could it be a smart and maintainable way?

Last question is if I have null value for a property. How could I configure the person-binding-xml file (oxm.file) to get the relative xml tag empty?

I could change the model class but I prefer don't add any lines of code if it's possible. (This is the reason why I populated the xml file)

So the result that I would like to obtain is:

 <?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>

For the second related question: I tried nillable="true" in but it doesn't work ! So For istance If I have a null value for a stringMap or firstName or something else I will get respectively and tag closed with any body.

Or another way that I would like to obtain is:

 <?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>

Thanks to all


Solution

  • I found the right solution:

            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 class:

            import java.util.ArrayList;
            import java.util.List;
    
            public class StringAdapterMap {
                 public List<StringEntryType> entry = new ArrayList<StringEntryType>();
    
            }
    

    StringEntryType class:

            public class StringEntryType {
    
                   public String key;
    
                   public String value;
    
            }
    

    in oxm.file remember to configure the adapter

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