После долгих поисков я наконец нашел ответ. Надеюсь, это поможет кому-то еще. В StackOverflow уже есть другие темы, связанные с этой проблемой, но, не зная правильных ключевых слов, я не нашел ответов.
Решением является использование LSResourceResolver для фабрики схем. а именно:
schemaFactory.setResourceResolver(new LSResourceResolver(){})
, где LSResourceResolver () отвечает за возврат ресурса include / import, который требуется XSD.
При поиске LSResourceResolver в SO найдено несколько полезных тем: https://stackoverflow.com/a/3830649/827480, https://stackoverflow.com/a/2342859/827480
Я постараюсь опубликовать свое собственное решение позже, когда у меня будет немного больше времени, но оно близко следует тому, что уже было предложено в двух вышеупомянутых ссылках (мое немного более упрощено с использованием строк вместо потоков ...) .
EDIT
Как и было обещано, вот фрагмент кода, с которым я закончил:
// 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;
}
КОНЕЦ РЕДАКТИРОВАНИЯ
Я надеюсь, что это может помочь кому-то еще в будущем.
Спасибо
Эрик