4

一个菜鸟问题。我正在从 dtd 文件 (USPTO dtd) 生成 Java 代码。DTD 指定根元素如下:

<!ELEMENT us-patent-grant (doc-page+ | (us-bibliographic-data-grant , abstract* , drawings? , description , us-sequence-list-doc? , us-megatable-doc?,table-external-doc* , us-chemistry* , us-math* ,us-claim-statement , claims))>

当我使用以下绑定模式运行 xjc

    <?xml version="1.0"?>
    <xml-java-binding-schema version="1.0ea2">
       <element name="us-patent-grant" type="class" root="true"></element>
    </xml-java-binding-schema>

我看到生成了以下 Java 对象

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "docPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims"
    })
    @XmlRootElement(name = "us-patent-grant")
    public class UsPatentGrant {
       ....

    @XmlElements({
        @XmlElement(name = "doc-page", required = true, type = DocPage.class),
        @XmlElement(name = "us-bibliographic-data-grant", required = true, type = UsBibliographicDataGrant.class),
        @XmlElement(name = "abstract", required = true, type = Abstract.class),
        @XmlElement(name = "drawings", required = true, type = Drawings.class),
        @XmlElement(name = "description", required = true, type = Description.class),
        @XmlElement(name = "us-sequence-list-doc", required = true, type = UsSequenceListDoc.class),
        @XmlElement(name = "us-megatable-doc", required = true, type = UsMegatableDoc.class),
        @XmlElement(name = "table-external-doc", required = true, type = TableExternalDoc.class),
        @XmlElement(name = "us-chemistry", required = true, type = UsChemistry.class),
        @XmlElement(name = "us-math", required = true, type = UsMath.class),
        @XmlElement(name = "us-claim-statement", required = true, type = UsClaimStatement.class),
        @XmlElement(name = "claims", required = true, type = Claims.class)
    })
    protected List<Object> docPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims;

     .........

public List<Object> getDocPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims() {
    if (docPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims == null) {
        docPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims = new ArrayList<Object>();
    }
    return this.docPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims;
}

所以我的问题是如何更改长吸气剂的名称

getDocPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims

在绑定模式中?

先感谢您。

4

2 回答 2

2

这与其说是一个答案,不如说是你所怀疑的证据。

在 的JAXB/XJC源代码中com.sun.tools.xjc.reader.dtd.Element,在bind()方法中,您可以看到这段摘录,它遍历了 的子elementsElement

if(b.isRepeated || b.elements.size()>1) {
    // collection
    StringBuilder name = new StringBuilder();
    for( Element e : b.elements ) {
        if(name.length()>0)
            name.append("Or");
        name.append(owner.model.getNameConverter().toPropertyName(e.name));
    }
    ...
} else {
    // single property
    String name = b.elements.iterator().next().name;
            String propName = owner.model.getNameConverter().toPropertyName(name);
            ...
}

看起来它几乎没有机会在"Or"有多个子元素的情况下更改分隔符的顺序。

您可以在 中的其他地方看到bindInfo允许的自定义名称Element,但不在此处附近。除非其他人能发现它,否则重命名事物的机会似乎就到此为止了。简而言之,CElementPropertyInfothis 输出导致BeanGenerator.fieldsJDefinedClass.fields然后直接由 输出JDefinedClass.declareBody()

正如XJC 文档所说,DTD 支持仍处于试验阶段......

于 2018-04-12T18:56:52.220 回答
1

正如@df778899 提到的,如果您查看了下面的源代码,那么对此无能为力

CElementPropertyInfo p;
if(b.isRepeated || b.elements.size()>1) {
    // collection
    StringBuilder name = new StringBuilder();
    for( Element e : b.elements ) {
        if(name.length()>0)
            name.append("Or");
        name.append(owner.model.getNameConverter().toPropertyName(e.name));
    }
    p = new CElementPropertyInfo(name.toString(), REPEATED_ELEMENT, ID.NONE, null, null,null/*TODO*/, locator, !b.isOptional );
    for( Element e : b.elements ) {
        CClassInfo child = owner.getOrCreateElement(e.name).getClassInfo();
        assert child!=null; // we are requiring them to be classes.
        p.getTypes().add(new CTypeRef(child,new QName("",e.name),null,false,null));
    }

CElementPropertyInfo对象采用名称,唯一的修复方法是使用检测。所以我创建了一个maven项目

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.tarunlalwani</groupId>
    <artifactId>jxc-customizer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
            <!-- https://mvnrepository.com/artifact/javassist/javassist -->
        <!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
            <dependency>
                <groupId>org.javassist</groupId>
                <artifactId>javassist</artifactId>
                <version>3.22.0-GA</version>
            </dependency>
        </dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>
                            ${project.build.directory}/libs
                        </outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Premain-Class>com.xjc.javaagent.SimpleAgent</Premain-Class>
                        <Boot-Class-Path>libs/javassist-3.22.0-GA.jar</Boot-Class-Path>
                        <Class-Path>libs/javassist-3.22.0-GA.jar</Class-Path>
                    </manifestEntries>
                    <manifest>
                        <classpathPrefix>libs/</classpathPrefix>

                    </manifest>
                </archive>
            </configuration>
        </plugin>

    </plugins>
</build>

</project>

jxccustomizer/src/main/java/com/xjc/javaagent/SimpleAgent.java

package com.xjc.javaagent;

import java.lang.instrument.Instrumentation;

public class SimpleAgent {

    public static void premain(String agentArgs,
                               Instrumentation instrumentation){

        System.out.println("Starting Agent");
        SimpleClassFileTransformer transformer =
                new SimpleClassFileTransformer();
        instrumentation.addTransformer(transformer);
    }
}

jxccustomizer/src/main/java/com/xjc/javaagent/SimpleClassFileTransformer.java

package com.xjc.javaagent;

import javassist.*;

import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class SimpleClassFileTransformer implements
        ClassFileTransformer {

    public byte[] transform(ClassLoader loader,
                            String className, Class classBeingRedefined,
                            ProtectionDomain protectionDomain, byte[] classfileBuffer)
            throws IllegalClassFormatException {

        byte[] byteCode = classfileBuffer;
        if (className.endsWith("/CPropertyInfo")) {
            System.out.println("Loading class - " + className);
            try {
                ClassPool classPool = ClassPool.getDefault();
                CtClass ctClass = classPool.makeClass(
                        new ByteArrayInputStream(classfileBuffer));
                CtConstructor[] constructors = ctClass.getConstructors();
                for (CtConstructor c : constructors) {
                    c.insertBefore("{        String propFile = System.getProperty(\"XJC_REMAP\");\n" +
                            "        if (propFile != null)\n" +
                            "        {\n" +
                            "            System.out.println(\"External remap file provided\");\n" +
                            "            java.util.Properties props = new java.util.Properties();\n" +
                            "            try {\n" +
                            "                props.load(new java.io.FileInputStream(propFile));\n" +
                            "                java.util.Enumeration enums = props.propertyNames();\n" +
                            "                while (enums.hasMoreElements()) {\n" +
                            "                    String key = (String)enums.nextElement();\n" +
                            "                    String value = props.getProperty(key);\n" +
                            "                    try {\n" +
                            "                        System.out.println(\"Checking if \" + name + \" matches \" + key);\n" +
                            "                        java.util.regex.Pattern pat = java.util.regex.Pattern.compile(\"^\" + key +\"$\", java.util.regex.Pattern.CASE_INSENSITIVE);\n" +
                            "                        if (pat.matcher(name).find())\n" +
                            "                        {\n" +
                            "                            System.out.println(\"Replacing \" + name + \" with \" + value);\n" +
                            "                            name = value;\n" +
                            "                            break;\n" +
                            "                        }\n" +
                            "                    } finally {\n" +
                            "                        if (name == key) {\n" +
                            "                            System.out.println(\"Replacing \" + name + \" with \" + value);\n" +
                            "                            name = value;\n" +
                            "                        }\n" +
                            "                        break;\n" +
                            "                    }\n" +
                            "                }\n" +
                            "            } catch (java.io.IOException e) {\n" +
                            "                e.printStackTrace();\n" +
                            "            }\n" +
                            "        }}");
                }
                byteCode = ctClass.toBytecode();
                ctClass.detach();
                System.out.println("NO Exception occured");
            } catch (Throwable e) {
                System.out.println("Exception occurred");
                e.printStackTrace();
            }
        }

        return byteCode;
    }
}

上面的类可以加载指定的属性文件-DXJC_REMAP=<filepath>,格式如下

重映射属性

docPageOr.*=patentDocument

现在来测试解决方案。首先需要jar通过运行以下命令为代理生成

mvn clean package

接下来是创建一些测试dtd

绑定.xjb

<?xml version="1.0"?>
<xml-java-binding-schema>
    <options package="org"/>
    <element name="us-patent-grant" type="class" root="true"></element>
</xml-java-binding-schema>

测试.dtd

<?xml version="1.0" encoding="utf-8"?>
 <!-- DTD to write simple stories
      Made by Daniel K. Schneider / TECFA / University of Geneva
      VERSION 1.0
      30/10/2003 -->
<!ELEMENT us-patent-grant (doc-page+ | (us-bibliographic-data-grant , abstract* , drawings? , description , us-sequence-list-doc? , us-megatable-doc?,table-external-doc* , us-chemistry* , us-math* ,us-claim-statement , claims))>

现在使用它来运行代理xjc

$ export _JAVA_OPTIONS="-javaagent:/Users/tarun.lalwani/Desktop/tarunlalwani.com/tarunlalwani/workshop/ub16/so/jaxb/jxccustomizer/target/jxc-customizer-1.0-SNAPSHOT.jar -DXJC_REMAP=/Users/tarun.lalwani/Desktop/tarunlalwani.com/tarunlalwani/workshop/ub16/so/jaxb/remap.properties"

$ xjc -b binding.xjb -dtd testing.dtd
Picked up _JAVA_OPTIONS: -javaagent:/Users/tarun.lalwani/Desktop/tarunlalwani.com/tarunlalwani/workshop/ub16/so/jaxb/jxccustomizer/target/jxc-customizer-1.0-SNAPSHOT.jar -DXJC_REMAP=/Users/tarun.lalwani/Desktop/tarunlalwani.com/tarunlalwani/workshop/ub16/so/jaxb/remap.properties
objc[33035]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/xjc (0x10ed964c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x10eded4e0). One of the two will be used. Which one is undefined.
Starting Agent
Loading class 2 - com/sun/tools/internal/xjc/model/CPropertyInfo
inside try
Updating cons 1
Updating cons
NO Exception occured
parsing a schema...
External remap file provided
Checking if DocPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims matches docPageOr.*
Replacing DocPageOrUsBibliographicDataGrantOrAbstractOrDrawingsOrDescriptionOrUsSequenceListDocOrUsMegatableDocOrTableExternalDocOrUsChemistryOrUsMathOrUsClaimStatementOrClaims with patentDocument
compiling a schema...
org/Abstract.java
org/Claims.java
org/Description.java
org/DocPage.java
org/Drawings.java
org/ObjectFactory.java
org/TableExternalDoc.java
org/UsBibliographicDataGrant.java
org/UsChemistry.java
org/UsClaimStatement.java
org/UsMath.java
org/UsMegatableDoc.java
org/UsPatentGrant.java
org/UsSequenceListDoc.java

现在生成的文件的内容是根据需要

正确生成的输出

上述代码的 git repo 可在以下链接中找到

https://github.com/tarunlalwani/xjc-java-agent-customization

于 2018-04-14T20:23:07.453 回答