【问题标题】:MOXy XmlNameTransformer for Multiple Packages用于多个包的 MOXy XmlNameTransformer
【发布时间】:2014-03-17 18:04:35
【问题描述】:

我正在尝试使用 MOXy 为 XML 编组和模式生成自定义命名算法跨多个包的类

我正在关注Eclipse documentation,并且可以让它为一个班级工作:

@XmlNameTransformer(com.example.test.NameGenerator.class)
public class Customer

或单个包:

@XmlNameTransformer(com.example.test.NameGenerator.class)
package com.example.test;

(外部绑定文件也可以,但您只能为每个绑定文件指定包)

然而,由于我的对象跨越多个包,我不想为每个包定义转换器。此外,我想动态地执行此操作(即各个包直到运行时才知道)。

我尝试在父包 (com.example) 中定义转换器,但这不起作用——看起来它需要是带注释的类所在的确切包。

有什么想法吗?

更新 - 更多信息

也许我应该提到我尝试这样做的主要原因是我可以控制 XML/XSD 的生成——最具体地说,我希望复杂类型为大写而不是默认的小写(不需要注释每个类),例如

@XmlRootElement
public class Test ...

应该生成:

<Test>
...
</Test>

而不是

<test>
...
</test>

根据我所做的其他研究,我发现这样做的唯一方法是使用XmlNameTransformer。但如果有另一种方法,而我找错了树……一定要告诉我!

【问题讨论】:

    标签: java xml jaxb marshalling moxy


    【解决方案1】:

    扩展 Blaise 的答案,这就是我的实现的样子。这通过对一组动态包使用转换器来完成。

    import org.eclipse.persistence.jaxb.metadata.MetadataSourceAdapter;
    import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings;
    import org.eclipse.persistence.jaxb.xmlmodel.XmlSchema;
    
    public class NameTransformerAdapter extends MetadataSourceAdapter {
    
        private XmlBindings bindings;
    
        /**
         * @param packageName Fully qualified package name, like {@code com.example.test}
         */
        public NameTransformerAdapter(String packageName) {
                bindings = new XmlBindings();
                bindings.setPackageName(packageName);
                bindings.setXmlNameTransformer(XmlNameTransformer.class.getName());
                bindings.setXmlSchema(new XmlSchema()); // this is necessary
        }
        @Override
        public XmlBindings getXmlBindings(Map<String, ?> properties, ClassLoader classLoader) {
                return bindings;
        }
    }
    

    引用的转换器非常简单:

    import org.eclipse.persistence.oxm.XMLNameTransformer;
    
    public class XmlNameTransformer implements XMLNameTransformer {
    
        /** Uses capitalized name of class */
        public String transformTypeName(String name) {
                return name.substring(name.lastIndexOf('.') + 1);
        }
        public String transformElementName(String name) {
                return name;
        }
        public String transformAttributeName(String name) {
                return name;
        }
        public String transformRootElementName(String name) {
                return transformTypeName(name);
        }
    }
    

    包在运行时确定并被跟踪:

    List<MetadataSource> adapters = new ArrayList<MetadataSource>();
    adapters.add(new NameTransformerAdapter(packageName));
    

    最后,可以使用上述适配器获取 JAXBContext:

    import org.eclipse.persistence.jaxb.JAXBContextFactory;
    import org.eclipse.persistence.jaxb.JAXBContextProperties;
    
    private JAXBContext getContext(Class<?>[] classes) throws JAXBException {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, adapters);
        return JAXBContextFactory.createContext(classes, properties);
    }
    

    【讨论】:

      【解决方案2】:

      包级别是您可以指定 MOXy/JAXB 元数据的最大范围。您可以使用 XmlNameTransformer 的相同实现,但您需要为每个要应用它的包指定它。

      但是,由于我的对象跨越多个包,我 不想为每个包定义变压器。 另外我想动态地做到这一点(即个人 包直到运行时才知道)。

      您可以通过编程方式创建与外部映射文档对应的对象模型。然后你可以在创建JAXBContext时传递this的实例。

      【讨论】:

      • 这太棒了——谢谢!我不敢相信我错过了 MetadataSource 作为 OXM_METADATA_SOURCE 属性类型。我将在另一个答案中扩展您的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多