Ali*_*lix 6 xml binding jaxb xjc
是否有任何 JAXB 绑定可以告诉 JAXB 代码生成器生成 Java 类,而abstract
不必像abstract
XSD 中那样标记相应的 XML 类型?
情况如下:
mySchema.xsd
我使用内联 JAXB 绑定(“内联”==“直接在架构中”)来指示应在其中生成 JAXB 类的包 ( my.package.jaxb
):
<xs:annotation>
<xs:appinfo>
<jxb:schemaBindings>
<jxb:package name="my.package.jaxb"/>
</jxb:schemaBindings>
</xs:appinfo>
</xs:annotation>
Run Code Online (Sandbox Code Playgroud)我使用内联 JAXB 绑定来指示每个复杂类型的实现类的名称(在本例中为my.package.impl.MyAbstractClass
、my.package.impl.MyAClass
和my.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>
Run Code Online (Sandbox Code Playgroud)我从架构生成 JAXB 类。这导致:
my.package.jaxb
|- MyAbstractType
|- MyAType (extends MyAbstractClass)
|- MyBType (extends MyAbstractClass)
Run Code Online (Sandbox Code Playgroud)我自己写类:
my.package.impl
|- MyAbstractClass (extends MyAbstractType)
|- MyAClass (extends MyAType)
|- MyBClass (extends MyBType)
Run Code Online (Sandbox Code Playgroud)我这样做的原因是,使用这两个类层次结构,以便我可以将生成的代码 ( my.package.jaxb.*
) 与手册 ( my.package.impl.*
) 分开。这样,当 XSD 发生更改时,我可以重新生成my.package.jaxb.*
类并在我的手动类中进行一些更改my.package.impl.*
以合并新行为。
到目前为止,一切都很好。问题是MyAbstractClass
我想定义一个抽象方法......
<xs:annotation>
<xs:appinfo>
<jxb:schemaBindings>
<jxb:package name="my.package.jaxb"/>
</jxb:schemaBindings>
</xs:appinfo>
</xs:annotation>
Run Code Online (Sandbox Code Playgroud)
MyAClass
...然后由和进行不同的实现MyBClass
。但是,生成的MyAType
和MyBType
类现在存在编译错误,因为它们没有声明为抽象,但它们现在继承了一个抽象方法(请注意,它们都扩展了MyAbstractClass
)。
我无法在 XSD ( abstract="true"
) 中将它们声明为抽象,因为每当我声明类型元素myAType
或myBType
在 XML 中时,这样做都会导致以下错误:
cvc-type.2: The type definition cannot be abstract for element someElementName.
Run Code Online (Sandbox Code Playgroud)
我想要的是使用一些 JAXB 绑定来告诉 JAXB 代码生成器生成类MyAType
,MyBType
而不abstract
必将 XML 类型标记为abstract
. 有这样的绑定吗?到目前为止我还没有找到它。
抱歉这么长的解释,并提前致谢。
我最终创建了一个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;
}
}
Run Code Online (Sandbox Code Playgroud)
这里的abstract.xsd
,它定义了<abstract>
您需要用来指示生成的类应该是抽象的元素:
<?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>
Run Code Online (Sandbox Code Playgroud)
用法(按照我原来问题中的示例):
<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>
Run Code Online (Sandbox Code Playgroud)
我不得不说,我发现很难找到所有必要的文档来弄清楚如何做到这一点。如果我有时间,我会在这里发布更长的解释;现在我希望至少代码能有所帮助。免责声明:我不知道这是否是最好的方法,但我必须依赖的类的文档记录非常松散(恕我直言,设计得不是很好),这是我能想到的最好方法。
我希望这有帮助。如果有人想使用此代码,请继续。