当前位置: 首页 > 面试题库 >

如何控制JAXB内存中架构生成的顺序/顺序?

别兴国
2023-03-14
问题内容

我有3个相互依赖的xsd文件来构建我的元素定义。每个xsd文件都有其自己的名称空间。当我使用JAXB
xjc生成类时,得到3个相应的包。到目前为止,一切都很好。

当我想使用解组器进行架构验证时,就会出现我的问题。为了避免不得不读取xsd文件,我从被解组的相关类中动态生成了模式。但是,由于该类依赖于其他2个包中的对象,因此除非我指定所有3个包,否则它无法生成架构。这已经不是一个非常实用的解决方案,因为它要求我提前知道对象层次结构/依赖关系树,并相应地指定包列表。

当我尝试使用SchemaFactory(SchemaFactory.newSchema(Source
[]))从3个生成的架构中创建新架构时,我遇到了更大的问题。显然,将架构提供给架构工厂的顺序对于解析依赖关系至关重要。如果数组中的第一个架构依赖于数组中最后一个元素的类型定义,则会收到解决错误:

org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'ns1:InCalculationDataType' to a(n) 'type definition' component.

如果我修改顺序,然后将第三个架构放在第一位,那么它将成功执行而不会出现错误。

这使得几乎不可能编写一种相当通用的方法,而不得不为每种XSD情况单独编写代码。

我有什么办法可以减轻这个问题?有什么方法可以迫使SchemaFactory首先读取所有内容,然后在发现任何错误时才生成错误?我知道您可以创建一个ErrorHandler,但是JavaDocs指出,如果抛出致命错误,则任何进一步的处理都是不可靠的。

编辑

只是为了让我省心,我试图创建一个错误处理程序,该程序忽略了非致命错误(只是记录了它们),但是生成的模式不可靠,无法正确验证xml错误。因此,它对我没有任何价值。

结束编辑

任何建议或想法将不胜感激。

谢谢!

埃里克


问题答案:

经过大量搜索,我终于找到了答案。希望这会帮助其他人。已经存在与此问题相关的其他线程,但是在不知道正确的关键字的情况下,我找不到响应。

解决方案是对架构工厂使用LSResourceResolver。即:

schemaFactory.setResourceResolver(new LSResourceResolver(){})

LSResourceResolver()负责返回XSD所需的包含/导入资源。

搜索LSResourceResolver的SO中发现一些有用的主题:http://codingdict.com/questions/155814

我将在以后有更多时间的时候尝试发布自己的解决方案,但它会紧跟上述两个链接中已经提出的建议(通过使用Strings而不是stream简化了我的工作…)。

编辑

如所承诺的,这是我最后得到的代码片段:

        // get the schemas used by this class
        final Map<String, String> schemas = new HashMap<String,String>();
        schemas.putAll(generateSchemas(jc));

        List<StreamSource> sources = new ArrayList<StreamSource>();
        for( String schema : schemas.values() )
            sources.add( new StreamSource( new ByteArrayInputStream(schema.getBytes())));

        SchemaFactory sf = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
        sf.setResourceResolver(new LSResourceResolver() {
            @Override
            public LSInput resolveResource(String type, final String namespaceURI, String publicId, String systemId, String baseURI){
                logger.debug( "Need to resolve Resource: " + namespaceURI );
                return new LSInput(){
                    @Override
                    public String getStringData() {
                        // return the schema if found
                        if( schemas.containsKey(namespaceURI)){
                            if( logger.isTraceEnabled())
                                logger.trace("resourceResolver: Resolving schema for namespace: " + namespaceURI + schemas.get(namespaceURI) );
                            return schemas.get(namespaceURI);
                        }
                        else
                            return null;
                    }
                    @Override
                    public Reader getCharacterStream() {
                        return null;
                    }
                    @Override
                    public void setCharacterStream(Reader paramReader) {
                    }
                    @Override
                    public InputStream getByteStream() {
                        return null;
                    }
                    @Override
                    public void setByteStream(InputStream paramInputStream) {
                    }
                    @Override
                    public void setStringData(String paramString) {
                    }
                    @Override
                    public String getSystemId() {
                        return null;
                    }
                    @Override
                    public void setSystemId(String paramString) {
                    }
                    @Override
                    public String getPublicId() {
                        return null;
                    }
                    @Override
                    public void setPublicId(String paramString) {
                    }
                    @Override
                    public String getBaseURI() {
                        return null;
                    }
                    @Override
                    public void setBaseURI(String paramString) {
                    }
                    @Override
                    public String getEncoding() {
                        return null;
                    }
                    @Override
                    public void setEncoding(String paramString) {
                    }
                    @Override
                    public boolean getCertifiedText() {
                        return false;
                    }
                    @Override
                    public void setCertifiedText(boolean paramBoolean) {
                    }
                };
            }
        });

        // validate the schema
        u.setSchema(sf.newSchema(sources.toArray(new StreamSource[]{})));

和方法generateSchemas(jc):

private Map<String, String> generateSchemas (JAXBContext jaxbContext) throws JAXBException{
    // generate the schemas
    final Map<String, ByteArrayOutputStream> schemaStreams = new LinkedHashMap<String,ByteArrayOutputStream>();

    try {
        jaxbContext.generateSchema(new SchemaOutputResolver(){
            @Override
            public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                logger.debug( "GenerateSchemas: adding namespace: " + namespaceUri);
                schemaStreams.put(namespaceUri, out);
                StreamResult streamResult = new StreamResult(out);
                streamResult.setSystemId("");
                return streamResult;
            }});
    } catch (IOException e) {
        // no IO being performed.  Can safely ignore any IO exception.
    }

    // convert to a list of string
    Map<String,String> schemas = new LinkedHashMap<String,String>();
    for( Map.Entry<String, ByteArrayOutputStream> entry : schemaStreams.entrySet() ){
        String schema = entry.getValue().toString();
        String namespace = entry.getKey();
        schemas.put(namespace, schema);
    }

    // done
    return schemas;
}

结束编辑

我希望这可以在将来对其他人有所帮助。

谢谢,



 类似资料:
  • 3.1 顺序控制结构 程序是一个语句序列,执行程序就是按特定的次序执行程序中的语句。程序中执行点的 变迁称为控制流程,当执行到程序中的某一条语句时,也说控制转到了该语句。由于复杂问 题的解法可能涉及复杂的执行次序,因此编程语言必须提供表达复杂控制流程的手段,称为 编程语言的控制结构。 程序的控制流程可以用流程图(flowchart)来形象地表示。流程图采用标准化的图形符 号来描述程序的执行步骤,是

  • 主要内容:顺序表的初始化顺序表,全名 顺序存储结构,是 线性表的一种。通过《 什么是线性表》一节的学习我们知道,线性表用于存储逻辑关系为“一对一”的数据,顺序表自然也不例外。 不仅如此,顺序表对数据的物理存储结构也有要求。 顺序表存储数据时,会提前申请一整块足够大小的物理空间,然后将数据依次存储起来,存储时做到数据元素之间不留一丝缝隙。 例如,使用顺序表存储集合  ,数据最终的存储状态如图 1 所示: 图 1 顺序存储结

  • 主要内容:图的顺序存储结构C语言实现使用图结构表示的数据元素之间虽然具有“多对多”的关系,但是同样可以采用顺序存储,也就是使用数组有效地存储图。 使用数组存储图时,需要使用两个数组,一个数组存放图中顶点本身的数据(一维数组),另外一个数组用于存储各顶点之间的关系(二维数组)。 存储图中各顶点本身数据,使用一维数组就足够了;存储顶点之间的关系时,要记录每个顶点和其它所有顶点之间的关系,所以需要使用二维数组。 不同类型的图,存储的方式略

  • 顺序结构 #include <stdio.h> #include <stdlib.h> int main01(void) { printf("%d \n", 1);//顺序结构,从上往下执行,从main函数开始 printf("%d \n", 11); printf("%d \n", 111); printf("%d \n", 1111); sys

  • 问题内容: 当前,我的项目使用,因此当我按此列排序时,它是根据中的顺序进行排序的,效果很好。但是我需要在中添加一些附加值,这些附加值需要插入到枚举值列表中的不同位置,并且不能仅仅添加到底部以保持正确的排序顺序。 如果这样做,我的数据库将会混乱。我将不得不编写一些脚本来将所有这些序数值转换为正确的新序数。有可能以后必须添加更多状态。由于必须修复数据库中的所有数据,因此只需要执行一次,因为这将是一项艰

  • 我在项目中使用JMH基准测试。我用@Benchmark注释了方法1和方法2。我希望顺序是:method1、method2、method 1、methad2……等等……这意味着:我希望方法2紧跟在方法1之后。有办法做到这一点吗? 谢谢大家!