У меня есть класс 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;}
}
}