当前位置: 首页 > 知识库问答 >
问题:

使用JAXB XMLAnyElement类型的样式返回动态元素名称

司空凌
2023-03-14

我在这些论坛上读到了很多答案,还有其他的博客文章,但我似乎无法将这些部分联系起来。

因此,我们从包含映射属性的基本POJO开始。已经确定了如何包装它,但这会返回一些值。我要做的是获取then名称(又称标签),并使其成为有效的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 dream团队之类的东西获得类似的结果?顺便说一下,如果考虑到这一点,我正在使用RESTEasy。

以下是带有@xmlanyement JAXBElement的论坛帖子:带有JAXB的动态标记名

共有2个答案

姚飞昂
2023-03-14

根据上面列出的解决方案,我加入了这个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;
    }

}

我已经在这里发布了全文(另一篇文章),这里还提供了评论和示例。。

郑桐
2023-03-14

我离答案不远——经过更多的实验,我找到了正确的组合。

为不可映射的返回类型创建包装器类。包装器应该包含/返回List

public class MapWrapper {
   @XmlAnyElement
    public List<JAXBElement<String>> properties = new ArrayList<JAXBElement<String>>();
}

创建一个向MapWrapper封送的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;
}
}

使用XmlAdapter注释不可映射类型

@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

结果应该是:

<someBean>
   <properties>
     <myProperty1>My Value 1</myProperty1>
     <myProperty2>My Value 1</myProperty2>
   </properties>
</someBean>

希望这能帮助别人!

 类似资料:
  • 问题内容: 我有一个div的特定样式表。现在我想使用js动态修改div的一个属性。 我该怎么做? 它是否正确? 问题答案: 几乎是正确的。 由于是JavaScript操作符,因此您实际上不能在属性名称中使用它。如果您正在设置,或者类似的单字,您的代码就可以正常工作。 但是,对于任何带连字符的属性名称,您都需要记住的是,在javascript中,您删除了连字符,并使下一个字母变为大写,因此应为。 还

  • 问题内容: 干草我有这样的元素 不幸的是,此类名称来自电子商务应用程序,无法更改。 我可以在班级名称上打点吗? 喜欢 问题答案: 但是,周围可能会有一些浏览器不支持此功能。

  • 问题内容: 我有一个模块分开的应用程序。有几个实体和CSV模块。CSV模块仅支持struct(Entity),但我想使CSV模块可与任何类型的实体一起使用。现在,它的工作方式如下:Csv模块从通道接收数据并将其严格转换为struct。我如何实现动态返回类型,因此它可以与任何类型的Entity一起使用,而不仅限于 问题答案: 快速/肮脏的解决方案: 返回接口{},但是您最终欺骗了编译器,而类型检查的

  • 我有一个静态的通用FormBuilder超文本标记语言助手方法(HTMLHelper类上的扩展方法),它接受视图模型类型的通用参数,然后当从数据库传递一个或多个字符串属性名称时,生成一个超文本标记语言形式在ASP. NET MVC 5.1 with. NET 4.5中。 我有一个公共方法来生成表单,还有单独的私有方法来生成表单中的“模块”部分,然后渲染其中的每个字段。类型参数从上到下沿此链传递。

  • 问题内容: 使用MVC时,返回即席Json很容易。 我正在使用新的Web API寻找此功能。 由于无法处理匿名类型,因此引发了异常。 我有这个替换此JsonNetFormatter基于 Json.Net 。如果我使用这行得通 但是如果我不返回,我看不到使用Web API的意义,那么最好还是坚持使用香草MVC。如果我尝试使用: 它序列化整个。 谁能指导我找到一种解决方案,在其中可以返回匿名类型? 问

  • 问题内容: 我在这里多次看到类似的问题,但有一个很大的不同。 在其他问题中,返回类型将由参数确定。我想要/需要做的是通过解析后的值确定返回类型。从我收集到的信息来看,以下方法可行: 我只是想确保在我搞砸任何东西之前,它有机会工作。提前致谢。 问题答案: 你做不到 Java返回类型必须是固定的基本类型或对象类。我敢肯定,您能做的最好的事情就是返回一个包装器类型,该包装器类型具有可获取各种可能类型的值