Тестирование преобразования Geo не удается в maven, работает в eclipse

В нашем текущем проекте мы используем установку maven для управления зависимостями и запуска модульных тестов. В какой-то момент разработки один из наших тестов перестал работать (мы не уверены, в какой именно момент, поэтому не знаем, что именно изменилось). Конкретная ошибка - это преобразование из декартовых координат в географические с использованием геоинструментов (пробовали 9 и 9.1). Самое интересное, что тот же тест отлично работает в eclipse. Мы много работали над анализом проблемы и создали минимальный пример, который показывает поведение, которое мы видим, где мы (разумно) уверены, что это не проблема пути к классам.

Пример

пом.xml

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.geotest</groupId>
    <artifactId>geotest</artifactId>
    <name>geotest</name>
    <version>1.0.0</version>
    <description></description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <geotools.version>9.1</geotools.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-main</artifactId>
            <version>${geotools.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.0</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.example.geotest.Geotest</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>maven2-repository.dev.java.net</id>
            <name>Java.net repository</name>
            <url>http://download.java.net/maven/2</url>
        </repository>
        <repository>
            <id>osgeo</id>
            <name>Open Source Geospatial Foundation Repository</name>
            <url>http://download.osgeo.org/webdav/geotools/</url>
        </repository>
    </repositories>
</project>

Тестер.java

package com.example.geotest;

import java.awt.geom.Point2D;
import java.util.Collections;
import java.util.Map;

import org.geotools.referencing.CRS;
import org.geotools.referencing.ReferencingFactoryFinder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.referencing.cs.DefaultCartesianCS;
import org.geotools.referencing.factory.ReferencingFactoryContainer;
import org.geotools.referencing.operation.DefaultConversion;
import org.geotools.referencing.operation.DefiningConversion;
import org.junit.Test;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.crs.CRSFactory;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.TransformException;

public class Tester {

    @Test
    public void testtesttest() throws Exception {

        // prepare actuall action
        final MathTransformFactory mtFactory = ReferencingFactoryFinder.getMathTransformFactory(null);
        final ReferencingFactoryContainer factories = new ReferencingFactoryContainer(null);
        final GeographicCRS geoCRS = DefaultGeographicCRS.WGS84;
        final CartesianCS cartCS = DefaultCartesianCS.GENERIC_2D;

        ProjectedCRS projCRS;
        MathTransform transformGeoToCrs;
        MathTransform transformCrsToGeo;


        ParameterValueGroup parameters = mtFactory.getDefaultParameters("Transverse_Mercator");
        parameters.parameter("central_meridian").setValue(9);
        parameters.parameter("latitude_of_origin").setValue(0.0);
        //0.9996 (a reduction of 1:2500); (40 cm/km)
        parameters.parameter("scale_factor").setValue(0.9996);
        //500 km for north hemisphere
        parameters.parameter("false_easting").setValue(500000.0);
        //10,0000 km for south hemisphere
        parameters.parameter("false_northing").setValue(0.0);

        Map<String, String> properties = Collections.singletonMap("name", "WGS 84 / UTM Zone 32");

        CRSFactory crsFactory = factories.getCRSFactory();
        DefiningConversion conv = new DefiningConversion("test", parameters);
        projCRS = crsFactory.createProjectedCRS(properties, geoCRS, conv, cartCS);
        transformGeoToCrs = CRS.findMathTransform(geoCRS, projCRS);
        transformCrsToGeo = CRS.findMathTransform(projCRS, geoCRS);

        // execute actual test
        double[] src = new double[] {5838597.0, 807147.75};
        double[] dest = new double[2];

        try {
            // this fails in maven
            transformCrsToGeo.transform(src, 0, dest, 0, 1);
        } catch (TransformException e) {
            throw new RuntimeException(e);
        }

        Point2D.Double geo = new Point2D.Double(dest[0], dest[1]);
    }
}

Если мы вызовем «mvn test», мы получим следующее исключение:

Tests in error:
    testtesttest(com.example.geotest.Tester): org.geotools.referencing.operation.projection.ProjectionException: The transform result may be 9.478,277 meters away from the expected position. Are you sure that the input coordinates are inside this map projection area of validity? The point is located 43°20.6'E away from the central meridian and 5°19.1'N away from the latitude of origin. The projection is "Transverse_Mercator".

Если мы запустим тест JUnit из eclipse, это отлично работает. Любые идеи, почему это происходит или как мы можем этого избежать?


В качестве примечания: следующие три строки являются обходным путем для устаревшего метода factory.createProjectedCRS(properties, geoCRS, null, parameters, cartCS), если у кого-то есть лучшее решение, будьте моим гостем :)

CRSFactory crsFactory = factories.getCRSFactory();
DefiningConversion conv = new DefiningConversion("test", parameters);
projCRS = crsFactory.createProjectedCRS(properties, geoCRS, conv, cartCS);

person gsnerf    schedule 13.05.2013    source источник
comment
Возможно, стоит проверить версии зависимостей (9.1). Возможно, maven использует другую версию той же банки, что и eclipse. Посмотрите в целевом каталоге дополнительную информацию (надежные отчеты или что-то в этом роде).   -  person Joop Eggen    schedule 13.05.2013
comment
Оба, похоже, используют один и тот же файл jar из репозитория maven. Единственная реальная разница, которую мы могли видеть, заключалась в том, что eclipse вызывает junit напрямую, в то время как maven запускает его через плагин surefire. В обоих случаях даже кажется, что это одна и та же версия JUnit.   -  person gsnerf    schedule 13.05.2013
comment
Я вижу, что ваш тестер не соответствует соглашению об именах maven-surefire-plugin, который отвечает за запуск модульных тестов. Или, с другой стороны, ваш выложенный pom показывает не все, что нужно.   -  person khmarbaise    schedule 14.05.2013


Ответы (2)


У меня была та же проблема, и я мог решить ее, отключив утверждения во время надежных тестовых прогонов. Вам нужно добавить следующие строки в ваш pom:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <enableAssertions>false</enableAssertions>
            </configuration>
        </plugin>
person Werner Scholtes    schedule 27.08.2013
comment
Это то, что мы закончили делать также. Из того, что мы узнали из списка рассылки, причиной может быть ошибка на стороне геоинструментов, которая может быть исправлена... или нет, если ответ, который мы получили, на самом деле не имеет к этому никакого отношения :) - person gsnerf; 27.08.2013

Как сказал Вернер, проблему можно решить, отключив утверждение во время безошибочного запуска теста. Если вы хотите, чтобы утверждения были включены в остальной части вашего кода, вы можете отключить утверждения только в классе MapProjection, либо изменив свой POM:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
            <argLine>-da:org.geotools.referencing.operation.projection.MapProjection</argLine>
        </configuration>
    </plugin>

или в Java:

MapProjection.class.getClassLoader().setClassAssertionStatus(MapProjection.class.getName(), false);

Эта ошибка может возникнуть, даже если преобразованная точка находится в пределах 3 градусов от центрального меридиана зоны UTM (и фактическая ошибка преобразования незначительна) из-за ошибки в том, как геоинструменты оценивают свою точность ( https://osgeo-org.atlassian.net/browse/GEOT-4207 ). Эта ошибка не актуальна в случае OP, так как здесь точка находится далеко за пределами зоны UTM (около 40 градусов от центрального меридиана), а ошибка преобразования (около 10 километров) не является незначительной (для некоторых приложений).

person Jaan    schedule 07.02.2015
comment
Метод setClassAssertionStatus эффективен только в том случае, если класс MapProjection еще не загружен. Если вы собираетесь отключить утверждения из кода, вам нужно поместить эту строку где-то в начале запуска вашей программы. - person Ryan; 06.03.2015
comment
Это исправление для результата преобразования может быть проблема 0,095 метра. - person Ryan; 06.03.2015