使用独立应用程序向HTTPRepository添加数据时RDF4J RIO UnsupportedRDFormatException

时间:2016-12-01 09:50:35

标签: exception sesame rdf4j

我初始化了HTTPRepository,其中包含存储库的URL。我使用RepositoryConnection检索并添加(天气)数据到存储库。数据从Web服务检索,然后转换为RDF语句,并添加到存储库。这是由一个独立的应用程序定期完成的。

当我在IntelliJ中运行此应用程序时,一切正常。

要在服务器上运行此应用程序,我创建了一个jar文件(包含所有依赖项)。应用程序按预期启动,并且能够从存储库检索数据。

但是,当应用程序尝试写入数据到存储库时,我得到UnsupportedRDFormatException

org.eclipse.rdf4j.rio.UnsupportedRDFormatException: Did not recognise RDF format object BinaryRDF (mimeTypes=application/x-binary-rdf; ext=brf)
    at org.eclipse.rdf4j.rio.Rio.lambda$unsupportedFormat$0(Rio.java:568) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at java.util.Optional.orElseThrow(Optional.java:290) ~[na:1.8.0_111]
    at org.eclipse.rdf4j.rio.Rio.createWriter(Rio.java:134) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.rio.Rio.write(Rio.java:371) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.rio.Rio.write(Rio.java:324) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.http.HTTPRepositoryConnection.addModel(HTTPRepositoryConnection.java:588) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.http.HTTPRepositoryConnection.flushTransactionState(HTTPRepositoryConnection.java:662) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.http.HTTPRepositoryConnection.commit(HTTPRepositoryConnection.java:326) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.base.AbstractRepositoryConnection.conditionalCommit(AbstractRepositoryConnection.java:366) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.base.AbstractRepositoryConnection.add(AbstractRepositoryConnection.java:431) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at nl.wur.fbr.data.weather.WeatherApp.retrieveData(WeatherApp.java:122) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at nl.wur.fbr.data.weather.WeatherData$WeatherTask.run(WeatherData.java:105) [weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at java.util.TimerThread.mainLoop(Timer.java:555) [na:1.8.0_111]
    at java.util.TimerThread.run(Timer.java:505) [na:1.8.0_111]

发生错误的源代码是:

    public void retrieveData(){
        logger.info("Retrieving data for weather for app: "+ID+" ");
        RepositoryConnection connection = null;
        ValueFactory vf = SimpleValueFactory.getInstance();
        try {
            connection = repository.getConnection();

            // Retrieving the locations from the repository (no problem here).
            List<Location> locations = this.retrieveLocations(connection);
            List<Statement> statements = new ArrayList<>();

            // Retrieving weather data from each location and transforming it to statements.
            for(Location location : locations){
                List<Weather> retrievedWeather = weatherService.retrieveWeatherData(location.name,location.latitude,location.longitude);
                for(Weather weather : retrievedWeather){
                    BNode phenomenon = vf.createBNode();
                    statements.add(vf.createStatement(location.ID,WEATHER.HAS_WEATHER,phenomenon,rdfStoreGraph));
                    statements.addAll(weather.getStatements(phenomenon,vf,rdfStoreGraph));
                    statements = this.correctOMIRIs(statements,vf);
                }
            }

            // Adding data retrieved from the weather API
            // This is where the exception happens.
            connection.add(statements,rdfStoreGraph);

        } catch (Exception e) {
            logger.error("Could not retrievedata for weather app: '"+ID+"' because no monitor locations could be found.",e);
        } finally {
            if(connection != null){
                connection.close();
            }
        }
    }

HTTPRespository初始化为:

        repository = new HTTPRepository(rdfStore.toString());
        ((HTTPRepository)repository).setPreferredRDFFormat(RDFFormat.BINARY);
        ((HTTPRepository)repository).setPreferredTupleQueryResultFormat(TupleQueryResultFormat.BINARY);

我已尝试将格式更改为TURTLE。但它没有任何区别。

你能告诉我怎么解决这个问题吗?

NB。 RDF4J服务器和库都有版本2.0.1(rdf4j)。

2 个答案:

答案 0 :(得分:4)

  

要在服务器上运行此应用程序,我创建了一个jar文件(包含所有依赖项)。

你的问题是:你创造了一个&#34;胖罐&#34;并且可能没有正确合并SPI注册表文件。

RDF4J的Rio解析器(以及其他几个模块)使用Java的服务提供程序接口(SPI)机制来注册自己。此机制依赖于jar文件中META-INF\services中的文本文件,其中包含每个解析器实现的完全限定名称。

当您合并jar时出现问题:每个Rio解析器jar都有一个具有相同名称但内容不同的注册表文件。如果您使用类似maven程序集插件的内容来创建胖jar,则每个注册表文件都会被下一个注册表文件覆盖。结果是,最后,RDF4J只能找到一个解析器 - 最后将其注册表文件添加到fat jar的解析器。

解决方案是要么根本不创建胖jar,要么必须使用不同的技术来创建它,它会合并注册表文件而不是覆盖它们。 maven shade plugin有一个很好的配置选项:ServicesResourceTransformer

答案 1 :(得分:2)

我重新发布这篇文章是因为我坚持了几个小时。最后,我可以使用具有以下配置的 maven shade 插件生成一个可执行的 jar:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.4</version>
    <configuration>
        <filters>
            <filter>
                <artifact>*:*</artifact>
                <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                </excludes>
            </filter>
        </filters>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>${fully.qualified.main.class}</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

我将阴影插件与 ManifestResourceTransformer 一起用于创建指示我项目主类的可执行 jar,并与 ServicesResourceTransformer 一起用于处理 RDF4J 包命名,以避免一个解析器覆盖前一个解析器。此外,我必须包含过滤器部分,以避免由包签名产生的 JNI 错误。

我希望这对某人有用。

您好。