JAXB: XmlAdapter для карты с коллекцией в качестве значений - PullRequest
0 голосов
/ 21 января 2020

У меня есть класс Container с атрибутом Map. Map имеет Object s в качестве ключа, здесь Double для MWE и связанный Collection в качестве значений, здесь Collection<String> для MWE.

Я пытался маршаллировать Container и написал XmlAdapter работающую реализацию, вдохновленную этой веткой . Тем не менее, я не очень доволен результатом.

Я получаю

<container>
  <results>
    <loadSteps loadStep="1.0">
      <results>
        <result>result1-1</result>
        <result>result1-2</result>
        <result>result1-3</result>
      </results>
    </loadSteps>
    <loadSteps loadStep="2.0">
      <results>
        <result>result2-1</result>
        <result>result2-2</result>
      </results>
    </loadSteps>
  </results>
</container>

Я бы хотел получить

<container>
  <results>
    <loadStep="1.0">
      <result>result1-1</result>
      <result>result1-2</result>
      <result>result1-3</result>
    </loadStep>
    <loadStep="2.0">
      <result>result2-1</result>
      <result>result2-2</result>
    </loadStep>
  </results>

или подобное. Поэтому я хочу, чтобы loadStep был прямым ключом, без loadSteps, распаковывая List in ResultMapType

Это возможно?

С моей попыткой ничего не написано в results/.


MWE

  • Основной

    public static void main(String[] args) 
            throws 
                FileNotFoundException
               ,JAXBException
               ,ParserConfigurationException
               ,TransformerException
    {
    
        double step1 = 1.0;
        ArrayList<String> step1Result = new ArrayList<>(3);
        step1Result.add("result1-1");
        step1Result.add("result1-2");
        step1Result.add("result1-3");
    
        double step2 = 2.0;
        ArrayList<String> step2Result = new ArrayList<>(3);
        step2Result.add("result2-1");
        step2Result.add("result2-2");
    
        TreeMap<Double,ArrayList<String>> results = new TreeMap<>();
        results.put(step1,step1Result);
        results.put(step2,step2Result);
    
        Container container = new Container();
        container.setResults(results);
    
        // JAXB object
        Object jaxbElement = container;
    
        File file = new File("./container.xml");
        FileOutputStream fop = new FileOutputStream(file);
    
        // create JAXB context
        JAXBContext context = JAXBContext.newInstance(jaxbElement.getClass());
    
        // Creating the Document object
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.newDocument();
    
        // Marshaling the User object into a Document object
        Marshaller m = context.createMarshaller();
        m.marshal(jaxbElement, document);
    
        // writing the Document object to console
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
    
        // set the properties for a formatted output - if false the output will be on one single line
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
    
        DOMSource source = new DOMSource(document);
        StreamResult result = new StreamResult(fop);
        transformer.transform(source, result);
    }
    
  • Контейнер

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Container {
    
        @XmlJavaTypeAdapter(ContainerMapAdapter.class)
        private TreeMap<Double,ArrayList<String>> results;
    
        public void setResults(TreeMap<Double,ArrayList<String>> v){this.results = v;}
        public TreeMap<Double,ArrayList<String>> getResults(){return results;}
    
    }
    
  • ContainerMapAdapter

    public class ContainerMapAdapter
                extends
                    XmlAdapter<
                        ContainerMapAdapter.ResultMapType
                       ,Map<
                            Double
                           ,ArrayList<String>
                        >
                    >
    {
    
        @Override
        public ResultMapType marshal(Map<Double, ArrayList<String>> map) throws Exception {
            ResultMapType fbmt = new ResultMapType();
            for (Map.Entry<Double, ArrayList<String>> e : map.entrySet()) {
                ResultMapEntry entry = new ResultMapEntry();
                entry.setLoadStep(e.getKey());
                entry.setStepResults(e.getValue());
                fbmt.loadSteps.add(entry);
            }
            return fbmt;
        }
    
        @Override
        public Map<Double, ArrayList<String>> unmarshal(ResultMapType fbmt) throws Exception {
            Map<Double, ArrayList<String>> map = new HashMap<>();
            for (ResultMapEntry entry : fbmt.loadSteps) {
                map.put(entry.getLoadStep(), entry.getStepResults());
            }
            return map;
        }
    
        public static class ResultMapType {
            public List<ResultMapEntry> loadSteps = new ArrayList<>();
        }
    
        @XmlAccessorType(XmlAccessType.NONE)
        public static class ResultMapEntry {
    
            private Double step;
            private ArrayList<String> stepResults;
    
            public void setLoadStep(Double v) {this.step = v;}
            @XmlAttribute
            public Double getLoadStep() {return step;}
    
            public void setStepResults(ArrayList<String> v) {this.stepResults = v;}
    
            @XmlElementWrapper(name="results")
            @XmlElement(name="result")
            public ArrayList<String> getStepResults() {return stepResults;}
    
        }
    
    }
    


Попытка

    public class ContainerMapAdapter2
                extends
                    XmlAdapter<
                        ArrayList<ResultMapEntry>
                       ,Map<
                            Double
                           ,ArrayList<String>
                        >
                    >
    {

        @Override
        public ArrayList<ResultMapEntry> marshal(Map<Double, ArrayList<String>> map) throws Exception {
            ArrayList<ResultMapEntry> list = new ArrayList<>(map.size());
            for (Map.Entry<Double, ArrayList<String>> e : map.entrySet()) {
                ResultMapEntry entry = new ResultMapEntry();
                entry.setLoadStep(e.getKey());
                entry.setStepResults(e.getValue());
                list.add(entry);
            }
            return list;
        }

        @Override
        public Map<Double, ArrayList<String>> unmarshal(ArrayList<ResultMapEntry> fbmt) throws Exception {
            Map<Double, ArrayList<String>> map = new HashMap<>();
            for (ResultMapEntry entry : fbmt) {
                map.put(entry.getLoadStep(), entry.getStepResults());
            }
            return map;
        }

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

            private Double step;
            private ArrayList<String> stepResults;

            public void setLoadStep(Double v) {this.step = v;}
            @XmlAttribute
            public Double getLoadStep() {return step;}

            public void setStepResults(ArrayList<String> v) {this.stepResults = v;}

            @XmlElementWrapper(name="results")
            @XmlElement(name="result")
            public ArrayList<String> getStepResults() {return stepResults;}

        }

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...