Search code examples
javaeclipsemavenjunitgeotools

Testing a Geo Transformation fails in maven, works in eclipse


In our current project we use a maven setup to manage dependencies and run unit tests. At some point in development one of our tests stoped working (we are not sure at what point exactly, so we don't know what exactly changed). The specific thing failing is a transformation from cartesian to geographic coordinates using geotools (9 and 9.1 tried). The juicy part is that the same test works fine in eclipse. We heavily worked on analysing the problem and created a minimal example that shows the behavior we see where we are (reasonably) sure that it is not classpath problem.

The Example

pom.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>

Tester.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]);
    }
}

If we call a 'mvn test' on this we get the following exception:

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".

If we run the JUnit test from eclipse this works perfectly. Any ideas why this is happening or how we can avoid it?


As a side note: the following three lines are a workaround for the deprecated factories.createProjectedCRS(properties, geoCRS, null, parameters, cartCS) method, if anyone has a better solution be my guest :)

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

Solution

  • I had the same problem and could solve it by disabling assertions during surefire test runs. You need to add the following lines to your pom:

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <enableAssertions>false</enableAssertions>
                </configuration>
            </plugin>