我在这些论坛以及其他博客文章中已经阅读了很多答案,但我似乎无法将各个部分连接在一起。
因此,我们从包含Map属性的基本POJO开始。已经很好地确定了如何包装它,但这会返回一些值。我要做的是接受name(a.k.a。标签)并使其成为有效的XML'属性'。所以我们会得到一些价值。
我发现了一个例子(如果我能再次找到它会链接)如下:
@XmlAnyElement
public List<JAXBElement<String>> getXmlProperties() {
List<JAXBElement<String>> elements = new ArrayList<JAXBElement<String>>();
for (Map.Entry<String, String> property: properties.entrySet())
elements.add(new JAXBElement<String>(new QName(property.getKey()),
String.class, property.getValue()));
return elements;
}
这很好用,但我在Bean / Pojo类中有这个,它与GWT前端共享,因此不能包含对JAXBElement和QName的引用(需要源代码)。
那么,是否有办法使用XmlAdapter和JAXBElement / QName / XmlAnyElement梦之队获得类似的结果?顺便说一句,如果这个因素存在,我正在使用RESTEasy。
以下是@ XmlAnyElement + JAXBElement的论坛帖子:Dynamic tag names with JAXB
答案 0 :(得分:4)
我距离答案还不远 - 经过一些实验后我发现了正确的组合。
为不可映射的返回类型创建包装类。包装器应包含/返回带有List<JAXBElement<String>
的{{1}} Annotate包装器返回类型。
@XmlAnyElement
创建一个封送到MapWrapper的XmlAdapter
public class MapWrapper {
@XmlAnyElement
public List<JAXBElement<String>> properties = new ArrayList<JAXBElement<String>>();
}
使用XmlAdapter
注释您的不可映射类型public class MapAdapter extends XmlAdapter<MapWrapper, Map<String,String>> {
@Override
public MapWrapper marshal(Map<String,String> m) throws Exception {
MapWrapper wrapper = new MapWrapper();
List<JAXBElement<String>> elements = new ArrayList<JAXBElement<String>>();
for (Map.Entry<String, String> property: m.entrySet()) {
elements.add(new JAXBElement<String>(
new QName(getCleanLabel(property.getKey())),
String.class, property.getValue()));
}
wrapper.elements=elements;
return wrapper;
}
@Override
public Map<String,String> unmarshal(MapWrapper v) throws Exception {
// TODO
throw new OperationNotSupportedException();
}
// Return a lower-camel XML-safe attribute
private String getCleanLabel(String attributeLabel) {
attributeLabel = attributeLabel.replaceAll("[()]", "")
.replaceAll("[^\\w\\s]", "_").replaceAll(" ", "_")
.toUpperCase();
attributeLabel = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL,
attributeLabel);
return attributeLabel;
}
}
地图如:
@XmlRootElement
public class SomeBean {
@XmlJavaTypeAdapter(MapAdapter.class)
public LinkedHashMap<String, String> getProperties() {
return properties;
}
}
应该出现:
My Property 1 My Value 1
My Property 2 My Value 2
希望这有助于其他人!
答案 1 :(得分:-1)
取决于上面列出的解决方案,我进入了MapAdapter
,它解决了编组和解组过程。
@XmlType
public class MapWrapper{
private List<JAXBElement<String>> properties = new ArrayList<>();
public MapWrapper(){
}
@XmlAnyElement
public List<JAXBElement<String>> getProperties() {
return properties;
}
public void setProperties(List<JAXBElement<String>> properties) {
this.properties = properties;
}
@Override
public String toString() {
return "MapWrapper [properties=" + toMap() + "]";
}
public Map<String, String> toMap(){
//Note: Due to type erasure, you cannot use properties.stream() directly when unmashalling is used.
List<?> props = properties;
return props.stream().collect(Collectors.toMap(MapWrapper::extractLocalName, MapWrapper::extractTextContent));
}
@SuppressWarnings("unchecked")
private static String extractLocalName(Object obj){
Map<Class<?>, Function<? super Object, String>> strFuncs = new HashMap<>();
strFuncs.put(JAXBElement.class, (jaxb) -> ((JAXBElement<String>)jaxb).getName().getLocalPart());
strFuncs.put(Element.class, ele -> ((Element) ele).getLocalName());
return extractPart(obj, strFuncs).orElse("");
}
@SuppressWarnings("unchecked")
private static String extractTextContent(Object obj){
Map<Class<?>, Function<? super Object, String>> strFuncs = new HashMap<>();
strFuncs.put(JAXBElement.class, (jaxb) -> ((JAXBElement<String>)jaxb).getValue());
strFuncs.put(Element.class, ele -> ((Element) ele).getTextContent());
return extractPart(obj, strFuncs).orElse("");
}
private static <ObjType, T> Optional<T> extractPart(ObjType obj, Map<Class<?>, Function<? super ObjType, T>> strFuncs){
for(Class<?> clazz : strFuncs.keySet()){
if(clazz.isInstance(obj)){
return Optional.of(strFuncs.get(clazz).apply(obj));
}
}
return Optional.empty();
}
}
public class MapAdapter extends XmlAdapter<MapWrapper, Map<String, String>>{
@Override
public Map<String, String> unmarshal(MapWrapper v) throws Exception {
return v.toMap();
}
@Override
public MapWrapper marshal(Map<String, String> m) throws Exception {
MapWrapper wrapper = new MapWrapper();
for(Map.Entry<String, String> entry : m.entrySet()){
wrapper.addEntry(new JAXBElement<String>(new QName(entry.getKey()), String.class, entry.getValue()));
}
return wrapper;
}
}
我已发布完整帖子here (in another post),其中还提供了评论和示例..