Skip to content

Instantly share code, notes, and snippets.

@ricardojlrufino
Last active June 5, 2020 18:40
Show Gist options
  • Save ricardojlrufino/8b0094bcf9c74b630274af50fe7cd831 to your computer and use it in GitHub Desktop.
Save ricardojlrufino/8b0094bcf9c74b630274af50fe7cd831 to your computer and use it in GitHub Desktop.
JAXB - Serialize Map<String, Object> (problem)
package com.ricardojlrufino.rhmitool.controller.configuration.example;
public class Address {
private String street;
private String city;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
package com.ricardojlrufino.rhmitool.controller.configuration.example;
public interface CustomSerializer<T> {
String serialize(T value);
T deserialize(String value);
}
package com.ricardojlrufino.rhmitool.controller.configuration.example;
import java.awt.Point;
import java.util.Arrays;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(
Method.class,
KeyValue.class,
Address.class,
Point.class
);
KeyValueAdapter adapter = new KeyValueAdapter(jc);
adapter.addSerializer(Point.class, new PointSerializer());
Method action = new Method();
action.setParameters(Arrays.asList(new KeyValue("name1", 100),
new KeyValue("name2", new Point(1, 2)),
new KeyValue("addr", new Address())
));
Marshaller marshaller = jc.createMarshaller();
marshaller.setAdapter(adapter);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(action, System.out);
// Unmarshaller unmarshaller = jc.createUnmarshaller();
// unmarshaller.setAdapter(adapter);
// File xml = new File("/media/ricardo/Dados/Workspace/Arduino/RHMI-Tool/HMIController/src/main/java/com/ricardojlrufino/rhmitool/controller/configuration/example/test.xml");
// Method action = (Method) unmarshaller.unmarshal(xml);
// System.out.println(action.getParameters());
// JAXBContext conetxt = JAXBContext.newInstance(java.awt.Point.class);
// Marshaller marshaller = conetxt.createMarshaller();
//// marshaller.marshal( new JAXBElement(
//// new QName("","rootTag"),Point.class,new Point(1, 2)), System.out);
//
// QName rootElement = new QName("attrName");
// Object value = new Point(1, 2);
// Class<?> type = value.getClass();
// JAXBElement jaxbElement = new JAXBElement(rootElement, type, value);
// marshaller.marshal(jaxbElement, System.out);
}
}
package com.ricardojlrufino.rhmitool.controller.configuration.example;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(KeyValueAdapter.class)
public class KeyValue {
private String name;
private Object value;
public KeyValue() {
super();
}
public KeyValue(String name, Object value) {
super();
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
package com.ricardojlrufino.rhmitool.controller.configuration.jaxb;
import java.util.HashMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class KeyValueAdapter extends XmlAdapter<Element, KeyValue> {
private ClassLoader classLoader;
private DocumentBuilder documentBuilder;
private JAXBContext jaxbContext;
private HashMap<Class, CustomSerializer> serializers = new HashMap<>();
public KeyValueAdapter() {
classLoader = Thread.currentThread().getContextClassLoader();
}
public KeyValueAdapter(JAXBContext jaxbContext) {
this();
this.jaxbContext = jaxbContext;
}
public <T> void addSerializer(Class<T> key, CustomSerializer<T> value) {
serializers.put(key, value);
}
private DocumentBuilder getDocumentBuilder() throws Exception {
// Lazy load the DocumentBuilder as it is not used for unmarshalling.
if (null == documentBuilder) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
documentBuilder = dbf.newDocumentBuilder();
}
return documentBuilder;
}
private JAXBContext getJAXBContext(Class<?> type) throws Exception {
if (null == jaxbContext) {
// A JAXBContext was not set, so create a new one based on the type.
return JAXBContext.newInstance(type);
}
return jaxbContext;
}
@Override
public Element marshal(KeyValue parameter) throws Exception {
if (null == parameter) {
return null;
}
Object value = parameter.getValue();
Class type = value.getClass();
// Custom serializers..
CustomSerializer customSerializer = serializers.get(type);
if(customSerializer != null) {
value = customSerializer.serialize(value);
}
// 1. Build the JAXBElement to wrap the instance of Parameter.
QName rootElement = new QName(parameter.getName());
JAXBElement jaxbElement = new JAXBElement(rootElement, type, value);
// 2. Marshal the JAXBElement to a DOM element.
Document document = getDocumentBuilder().newDocument();
Marshaller marshaller = getJAXBContext(type).createMarshaller();
marshaller.marshal(jaxbElement, document);
Element element = document.getDocumentElement();
// 3. Set the type attribute based on the value's type.
element.setAttribute("type", type.getName());
return element;
}
@Override
public KeyValue unmarshal(Element element) throws Exception {
if (null == element) {
return null;
}
// 1. Determine the values type from the type attribute.
Class<?> type = classLoader.loadClass(element.getAttribute("type"));
// Custom serializers..
CustomSerializer customSerializer = serializers.get(type);
if(customSerializer != null) {
Object value = customSerializer.deserialize(element.getTextContent());
KeyValue parameter = new KeyValue();
parameter.setName(element.getLocalName());
parameter.setValue(value);
return parameter;
}else {
// 2. Unmarshal the element based on the value's type.
DOMSource source = new DOMSource(element);
Unmarshaller unmarshaller = getJAXBContext(type).createUnmarshaller();
JAXBElement jaxbElement = unmarshaller.unmarshal(source, type);
// 3. Build the instance of Parameter
KeyValue parameter = new KeyValue();
parameter.setName(element.getLocalName());
parameter.setValue(jaxbElement.getValue());
return parameter;
}
}
}
package com.ricardojlrufino.rhmitool.controller.configuration.example;
import java.util.List;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Method {
private String name;
private List<KeyValue> parameters;
@XmlAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlAnyElement
public List<KeyValue> getParameters() {
return parameters;
}
public void setParameters(List<KeyValue> parameters) {
this.parameters = parameters;
}
}
package com.ricardojlrufino.rhmitool.controller.configuration.example;
import java.awt.Point;
public class PointSerializer implements CustomSerializer<Point> {
@Override
public String serialize(Point value) {
return value.getX()+","+value.getY();
}
@Override
public Point deserialize(String value) {
return new Point();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment