Java 如何控制JAXB内存模式生成顺序/顺序?

Java 如何控制JAXB内存模式生成顺序/顺序?,java,validation,jaxb,schema,unmarshalling,Java,Validation,Jaxb,Schema,Unmarshalling,我有3个相互依赖的xsd文件来构建我的元素定义。每个xsd文件都有自己的名称空间。当我使用JAXBXJC生成类时,我得到了3个相应的包。到目前为止还不错 当我想用解组器进行模式验证时,我的问题就来了。为了避免必须读入xsd文件,我从正在解组的类动态生成模式。但是,由于该类依赖于其他2个包中的对象,因此除非我指定所有3个包,否则它无法生成模式。这已经不是一个非常实用的解决方案,因为它要求我提前知道对象层次结构/依赖关系树,并相应地指定包列表 当我尝试使用SchemaFactory(SchemaFa

我有3个相互依赖的xsd文件来构建我的元素定义。每个xsd文件都有自己的名称空间。当我使用JAXBXJC生成类时,我得到了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错误。因此,它对我毫无价值

结束编辑

如有任何建议或想法,将不胜感激

谢谢


埃里克

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

解决方案是为模式工厂使用LSResourceResolver。即:

schemaFactory.setResourceResolver(new LSResourceResolver(){})
其中LSResourceResolver()负责返回XSD所需的包含/导入资源

在中搜索LSResourceResolver时,发现了几个有用的线程:

当我有更多的时间时,我将尝试稍后发布我自己的解决方案,但它紧跟上面两个链接中已经建议的内容(我的解决方案通过使用字符串而不是流来简化…)

编辑

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

        // 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[]{})));
//获取此类使用的架构
最终映射模式=新HashMap();
schemas.putAll(generateSchemas(jc));
列表源=新的ArrayList();
for(字符串架构:schemas.values())
add(newstreamsource(newbytearrayinputstream(schema.getBytes()));
SchemaFactory sf=SchemaFactory.newInstance(xmlstants.W3C\u XML\u SCHEMA\u NS\u URI);
sf.setResourceResolver(新的LSResourceResolver(){
@凌驾
公共LSInput resolveResource(字符串类型、最终字符串namespaceURI、字符串publicId、字符串systemId、字符串baseURI){
debug(“需要解析资源:“+namespaceURI”);
返回新的LSInput(){
@凌驾
公共字符串getStringData(){
//如果找到,则返回架构
if(schemas.containsKey(namespaceURI)){
if(logger.isTraceEnabled())
trace(“resourceResolver:解析命名空间的架构:”+namespaceURI+schemas.get(namespaceURI));
返回schemas.get(namespaceURI);
}
其他的
返回null;
}
@凌驾
公共读取器getCharacterStream(){
返回null;
}
@凌驾
public void setCharacterStream(读卡器参数读卡器){
}
@凌驾
公共输入流getByTestStream(){
返回null;
}
@凌驾
公共数据流(InputStream参数InputStream){
}
@凌驾
公共void setStringData(字符串参数字符串){
}
@凌驾
公共字符串getSystemId(){
返回null;
}
@凌驾
public void setSystemId(字符串参数字符串){
}
@凌驾
公共字符串getPublicId(){
返回null;
}
@凌驾
public void setPublicId(字符串参数字符串){
}
@凌驾
公共字符串getBaseURI(){
返回null;
}
@凌驾
public void setBaseURI(字符串paramString){
}
@凌驾
公共字符串getEncoding(){
返回null;
}
@凌驾
公共void setEncoding(字符串paramString){
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;
}