Geotools cannot find HSQL EPSG DB, throws error: NoSuchAuthorityCodeException

Geotools uses Java's Service infrastructure to load the class responsible for EPSG lookups. The original gt-epsg-hsql.jar has entries in /META-INF/services/ which specify which interfaces are implemented by the jar-file, and which can be dynamically loaded at runtime.

When building a uber-jar, you combine multiple jar files into one. Most likely, another jar file implements the same interfaces as well (for example gt-referencing.jar) and has thus files with the same names in its /META-INF/services/. When putting everything into one jar file, those entries will very likely be overwritten (at least I couldn't find any reference that the maven-shade-plugin merges such services files).

You could verify that by looking at the services-directory in the created uber-jar, especially at the entry /META-INF/services/org.opengis.referencing.crs.CRSAuthorityFactory. Both gt-epsg-hsql.jar and gt-referencing.jar have such a file (and other jar-files from GeoTools probably as well), and most likely, only the content of one will be in your uber-jar, resulting in all the other classes not being found/loaded at runtime.

I'm not really familiar with the maven-shade-plugin, but other questions on SO (like [1]) suggest to use an additional transformer:

<transformer
   implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />

EDIT: As this answer gets regular visits, and I'm familiar with the shade plugin by now, here is a more detailed guide to use the shade-plugin.

So instead of using the maven-assembly plugin, we can use the maven-shade plugin to create an all-in-one jar. To do so, configure the maven-shade plugin indoor pom.xml and bind it to the package phase (so, whenever you call mvn package, the shaded jar will be created:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.1.0</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
          <configuration>
            <transformers>
              <!-- This bit sets the main class for the executable jar as you otherwise -->
              <!-- would with the assembly plugin                                       -->
              <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <manifestEntries>
                  <Main-Class>com.example.YourMainClass</Main-Class>
                  <Implementation-Vendor>Your Company Name</Implementation-Vendor>
                  <Implementation-Version>${project.version}</Implementation-Version>
                </manifestEntries>
              </transformer>
              <!-- This bit merges the various GeoTools META-INF/services files         -->
              <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
            </transformers>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

The Implementation-Vendor and Implementation-Version may not be needed in all cases, but I observed situations where some code (I think JAI - Java advanced imaging) complained and misbehaved when this information was missing, likely as the original JAR included such information and the shaded one did not by default, so it might be best to just include it.

When running mvn package, it will rename the original jar-file to something like original-myArtifact.jar and place the shaded (=all-in-one, fat-jar, uber-jar) at myArtifact.jar. If you don't like this behavior and want to keep the original jar file intact and have the shaded jar-file separat, add the following line inside the configuration block:

<shadedArtifactAttached>true</shadedArtifactAttached>

In this case, the build process will create a file myArtifact-shaded.jar (similar to myArtifact-jar-with-dependencies.jar created by the assembly plugin).


[1] Maven shade + resteasy Could find writer for content-type


I also ran into this problem. Instead of banging your head against the wall, there is a workaround you could use which is to create the CRS from WKT instead of using decode:

private static final String EPSG4326 = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]";
    CoordinateReferenceSystem worldCRS = CRS.parseWKT(EPSG4326);

One tip is that if you use this method, the resulting CRS will store the longitude first in the WKT followed by the latitude. Using the ServicesResourceTransformer gives WKT that has latitude followed by longitude. More on this issue at this link http://docs.geotools.org/latest/userguide/library/referencing/order.html


GeoTools uses a factory based plugin system to provide multiple referencing databases, but you have to choose one of them. gt-referencing provides the interfaces and the factory. The actual authorities are in the EPSG plugins (choose only one to prevent conflict):

  • EPSG HSQL Plugin
  • EPSG Access Plugin
  • EPSG PostgreSQL Plugin
  • EPSG WKT Plugin
  • Referencing 3D
  • EPSG Extension Plugin

For other problems with hsql db, you can enable debug logging for geotools.

Geotools uses default java logging. Add following entries to logging.properties config file.

org.geotools.level = FINEST
org.geotools.handlers = java.util.logging.ConsoleHandler

This file is usually located in %JAVA_HOME% or explicitly set by

-Djava.util.logging.config.file=logging.properties

runtime argument