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

从非抽象XML类型生成抽象Java类的JAXB绑定

尹正奇
2023-03-14

是否有任何JAXB绑定可以告诉JAXB代码生成器将Java类生成为abstract,而不必在XSD中将相应的XML类型标记为abstract

情况如下:

>

  • 我在xsd中定义架构:myschema.xsd
  • 我使用内联JAXB绑定(“inline”==“直接在模式中”)来指示应该生成JAXB类的包(my.package.JAXB):

    <xs:annotation>
        <xs:appinfo>
            <jxb:schemaBindings>
                <jxb:package name="my.package.jaxb"/>
            </jxb:schemaBindings>
        </xs:appinfo>
    </xs:annotation>
    

    我使用内联JAXB绑定为我的每个复杂类型(在本例中my.package.impl.MyAbstractClassmy.package.impl.MyAclassmy.package.impl.MybClass)指示实现类的名称:

    <xs:complexType name="myAbstractType" abstract="true">
        <xs:annotation>
            <xs:appinfo>
                <jxb:class implClass="my.package.impl.MyAbstractClass"/>
            </xs:appinfo>
        </xs:annotation>
        ...
    </xs:complexType>
    
    <xs:complexType name="myAType">
        <xs:annotation>
            <xs:appinfo>
                <jxb:class implClass="my.package.impl.MyAClass"/>
            </xs:appinfo>
        </xs:annotation>
        <xs:complexContent>
            <xs:extension base="myAbstractType">
                ...
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    
    <xs:complexType name="myBType">
        <xs:annotation>
            <xs:appinfo>
                <jxb:class implClass="my.package.impl.MyBClass"/>
            </xs:appinfo>
        </xs:annotation>
        <xs:complexContent>
            <xs:extension base="myAbstractType">
                ...
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    

    我从模式生成JAXB类。这导致:

    my.package.jaxb
       |- MyAbstractType
       |- MyAType (extends MyAbstractClass)
       |- MyBType (extends MyAbstractClass)
    

    我自己编写类:

    my.package.impl
       |- MyAbstractClass (extends MyAbstractType)
       |- MyAClass (extends MyAType)
       |- MyBClass (extends MyBType)
    

    使用这两个类层次结构这样做的原因是,我可以将生成的代码(my.package.jaxb.*)与手动代码(my.package.impl.*)分开。这样,当XSD中发生更改时,我可以重新生成my.package.jaxb.*类,并在我的手动my.package.impl.*类中进行一些更改,以合并新的行为。

    到目前为止还好。问题是在MyAbstractClass中,我想定义一个html" target="_blank">抽象方法······

    protected abstract void doSomething();
    

    ...然后由myaclassmybclass以不同的方式实现。但是,生成的MyAtypeMyBType类现在有编译错误,因为它们没有声明为抽象,而是继承了一个抽象方法(注意它们都扩展了MyAbstractClass)。

    我不能在XSD中将它们声明为抽象(abstract=“true”),因为每当我在XML中声明MyatypeMybtype类型的元素时,这样做将导致以下错误:

    cvc-type.2: The type definition cannot be abstract for element someElementName.
    

    我希望使用一些JAXB绑定来告诉JAXB代码生成器将类MyatypeMybtype生成为Abstract,而不必将XML类型标记为Abstract。有这样的绑定吗?到目前为止我还没能找到它。

    很抱歉解释得太长,并提前表示感谢。

  • 共有1个答案

    陆文斌
    2023-03-14

    我最终创建了一个XJC插件。代码如下:

    import java.lang.reflect.Method;
    
    import javax.xml.namespace.QName;
    
    import org.xml.sax.ErrorHandler;
    import org.xml.sax.SAXException;
    
    import com.sun.codemodel.JMod;
    import com.sun.codemodel.JMods;
    import com.sun.tools.xjc.Options;
    import com.sun.tools.xjc.outline.ClassOutline;
    import com.sun.tools.xjc.outline.Outline;
    import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIDeclaration;
    import com.sun.tools.xjc.reader.xmlschema.bindinfo.BindInfo;
    import com.sun.xml.xsom.XSAnnotation;
    
    public class AbstractModifierPlugin extends com.sun.tools.xjc.Plugin {
    
        private static final QName ABSTRACT_QNAME = new QName("http://www.example.com/jaxb/abstract-modifier/1-0", "abstract");
    
        private static final String SET_FLAG_METHOD_NAME = "setFlag";
    
        private static final String OPTION_NAME = "Xabstract-modifier";
    
        @Override
        public String getOptionName() {
            return OPTION_NAME;
        }
    
        @Override
        public String getUsage() {
            return " -" + OPTION_NAME + " : marks as abstract the generated classes corresponding to XML types marked with "
                    + "<xs:annotation><xs:appinfo><" + ABSTRACT_QNAME + "/></xs:appinfo></xs:annotation>";
        }
    
        @Override
        public boolean run(Outline outline, Options options, ErrorHandler errorHandler) throws SAXException {
            Method setFlagMethod = null;
            try {
                // There is no method to make a class abstract; we can only use setFlag, which is private, so
                // we must get it via reflection and make it accessible.
                setFlagMethod = JMods.class.getDeclaredMethod(SET_FLAG_METHOD_NAME, int.class, boolean.class);
                setFlagMethod.setAccessible(true);
            } catch (Throwable e) {
                System.err.println("There was an error retrieving the " + JMods.class.getName() + "." + SET_FLAG_METHOD_NAME
                        + " method (see below) => it will not be possible to set any class' abstract flag => this plugin will abort");
                e.printStackTrace();
                return false;
            }
    
            for (ClassOutline classOutline : outline.getClasses()) {
                if (hasAbstractAnnotation(classOutline)) {
                    try {
                        setFlagMethod.invoke(classOutline.implClass.mods(), JMod.ABSTRACT, true);
                    } catch (Throwable e) {
                        System.err.println("It was not possible to make " + classOutline.implClass.fullName()
                                + " abstract (see below)");
                        e.printStackTrace();
                    }
                }
            }
            return true;
        }
    
        protected boolean hasAbstractAnnotation(ClassOutline classOutline) {
            XSAnnotation annotation = classOutline.target.getSchemaComponent().getAnnotation();
            if (annotation != null) {
                Object innerAnnotation = annotation.getAnnotation();
                if (innerAnnotation instanceof BindInfo) {
                    for (BIDeclaration bindInfoDeclaration : (BindInfo) innerAnnotation) {
                        if (ABSTRACT_QNAME.equals(bindInfoDeclaration.getName())) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    
    }
    

    下面是abstract.xsd,它定义了 元素,您需要使用该元素来指示生成的类应该是抽象的:

    <?xml version="1.0" encoding="UTF-8"?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.example.com/jaxb/abstract-modifier/1-0"
        xmlns:tns="http://www.example.com/jaxb/abstract-modifier/1-0"
        elementFormDefault="qualified">
    
        <element name="abstract"/>
    
    </schema>
    

    用法(按照我最初问题中的示例):

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
        ...
        xmlns:abstract="http://www.example.com/jaxb/abstract-modifier/1-0"
        ...>
    
        <xs:complexType name="myAbstractType" abstract="true">
            <xs:annotation>
                <xs:appinfo>
                    <jxb:class implClass="my.package.impl.MyAbstractClass"/>
                </xs:appinfo>
            </xs:annotation>
            ...
        </xs:complexType>
    
        <xs:complexType name="myAType">
            <xs:annotation>
                <xs:appinfo>
                    <jxb:class implClass="my.package.impl.MyAClass"/>
                    <!-- This tells the AbstractModifierPlugin to make the
                    generated class abstract -->
                    <abstract:abstract/>
                </xs:appinfo>
            </xs:annotation>
            <xs:complexContent>
                <xs:extension base="myAbstractType">
                    ...
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    
        <xs:complexType name="myBType">
            <xs:annotation>
                <xs:appinfo>
                    <jxb:class implClass="my.package.impl.MyBClass"/>
                    <!-- This tells the AbstractModifierPlugin to make the
                    generated class abstract -->
                    <abstract:abstract/>
                </xs:appinfo>
            </xs:annotation>
            <xs:complexContent>
                <xs:extension base="myAbstractType">
                    ...
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    

    我不得不说,我发现很难找到所有必要的文档来找出如何做到这一点。如果我找到时间,我会在这里发布一个更长的解释;就目前而言,我希望至少代码会有所帮助。免责声明:我不知道这是否是最好的方法,但我必须依赖的类文档非常松散(而且设计得不是很好),这是我能想到的最好的方法。

    我希望这能有所帮助。如果有人想使用这个代码,请便。

     类似资料:
    • 错误CS0234:类型或命名空间名称com.sushi.hangover”中不存在。是否缺少程序集引用? 我有一个Android绑定项目,它有从多个接口继承的类,但这些接口没有生成,因此依赖于它们的所有公共类都无法绑定。 如您所见,该接口的没有设置为,因此不会生成C#代码,但是begin生成了依赖于该接口的公共类: 绑定在将接口名称从转换为时,可以识别接口。 是否有任何方法可以强制创建这些接口,而

    • 问题是: 我有一个叫做Schema的基类,它是抽象的,它是一个未生成的类。我有两个从Schema继承生成的JAXB类:FixedWidthSchema和DelimitedSchema。 我使用外部绑定(xjb)文件来指定XSD和Java类之间的映射。 在基类模式中,我定义了几个方法: 公共架构静态创建(Model m),它从提供的模型创建架构。 公共抽象Writer marshal(),它将当前架

    • 我目前正在尝试使用JaxB,但对于一个相对简单的示例,我并不是很成功。我的示例如下: 我所有的尝试(甚至编组)都失败了。我浏览了BlaiseDoughan的博客,包括http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html但他们似乎对我的例子都没有帮助。我很可能误用了他的例子。在我看来,我的示例应该是JaxB中

    • 问题内容: 我正在尝试使用JAXB解组一些XML,但出现“无法创建…的实例”异常。我知道为什么- 它试图建立一个抽象类的实例。我想要的是让它成为特定实现类的实例。我的目标是对setter方法进行特定于类的检查。对于BarImpl,也许“ qux”是有效的baz值,但BarImpl2想要做其他事情。 我没有通过注释Foo来实现这一目标,但是如果我不注释bar,事情就会变得很丑。 问题答案: 您可以执

    • 我有一个子类,它声明了我的抽象超类中的所有方法,但它仍然给我一个错误,说明我的类不是抽象的。我不知道为什么会抛出这个错误。 我得到的具体错误是 PhoneBookEntry.java: 1:错误:PhoneBookEntry不是抽象的,并且不会覆盖可比中的抽象方法compareTo(Object) 我的问题代码: 还有我的子类:

    • 问题内容: 我有一个包含带有抽象超类的JAXB注释类的程序包。我想在Web服务接口中使用此超类,因此可以将任何子类作为参数传递。当我这样做时,会引发异常: 可以手动将marshall / unmarshall&参数作为字符串传递,但我想避免这种情况。有什么想法怎么做? 问题答案: 您是否在Web服务请求中指定了具体的实现?这对我来说很好: 抽象基类: 实现类: Web服务方法: 请求: