{"id":4016,"date":"2024-06-05T13:28:17","date_gmt":"2024-06-05T17:28:17","guid":{"rendered":"https:\/\/cs4760.csl.mtu.edu\/2024\/?page_id=4016"},"modified":"2025-01-19T20:15:01","modified_gmt":"2025-01-20T01:15:01","slug":"gis-programming-using-geotools","status":"publish","type":"page","link":"https:\/\/cs4760.csl.mtu.edu\/2025\/lectures\/gis-programming-using-geotools\/","title":{"rendered":"GIS Programming Using GeoTools"},"content":{"rendered":"\n<p>GeoTools is an open source Java library for authoring GIS software and applications.&nbsp;<\/p>\n\n\n\n<p><a href=\"https:\/\/geotools.org\">https:\/\/geotools.org<\/a><\/p>\n\n\n\n<p>It is a fully equipped library adhering to the Open Geospatial Consortium (OGC) standards and providing graphical user interface (GUI).&nbsp;<\/p>\n\n\n\n<p><a href=\"https:\/\/docs.geotools.org\/latest\/userguide\/welcome\/standards.html\">https:\/\/docs.geotools.org\/latest\/userguide\/welcome\/standards.html<\/a><\/p>\n\n\n\n<p>This lecture demonstrates techniques for using GeoTools in a Grails app through the sequence of three projects:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>gradle-geotools<\/li>\n\n\n\n<li>grails-bean<\/li>\n\n\n\n<li>grails-geotools<\/li>\n<\/ol>\n\n\n\n<p>The final project, grails-geotools, focuses on using shapefiles for querying geographic information and rendering the information in a view.&nbsp;<\/p>\n\n\n\n<p>Before studying these projects, you should have some acquaintance with GeoTools and GIS terminology. I recommending doing a few lectures at GeoTools, at a minimum:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Maven Quickstart &#8211; <a href=\"https:\/\/docs.geotools.org\/latest\/userguide\/tutorial\/quickstart\/maven.html\">https:\/\/docs.geotools.org\/latest\/userguide\/tutorial\/quickstart\/maven.html<\/a><\/li>\n\n\n\n<li>Feature Tutorial &#8211; <a href=\"https:\/\/docs.geotools.org\/latest\/userguide\/tutorial\/feature\/csv2shp.html\">https:\/\/docs.geotools.org\/latest\/userguide\/tutorial\/feature\/csv2shp.html<\/a>&nbsp;<\/li>\n\n\n\n<li>Query Tutorial &#8211; <a href=\"https:\/\/docs.geotools.org\/latest\/userguide\/tutorial\/filter\/query.html\">https:\/\/docs.geotools.org\/latest\/userguide\/tutorial\/filter\/query.html<\/a><\/li>\n<\/ol>\n\n\n\n<p>GeoTools developers prefer to use Maven for their build tool.<\/p>\n\n\n\n<p><a href=\"https:\/\/maven.apache.org\">https:\/\/maven.apache.org<\/a><\/p>\n\n\n\n<p>Maven is one of the original Java build tools and is a substitute for Gradle. It is worthwhile becoming acquainted with it. Fortunately you can download it using SDKMAN.<\/p>\n\n\n\n<p><a href=\"https:\/\/sdkman.io\">https:\/\/sdkman.io<\/a><\/p>\n\n\n\n<p>Look for it using&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sdk list mvn<\/pre>\n\n\n\n<p>In the Maven Quickstart, you will learn how to display a shapefile in a SWING map. Shapefiles is ESRI standard for a geodatabase. The shapefile and the associated &#8220;side car&#8221; files are ESRI proprietary formats for representing geography and associated attributes. You can think of it as a geodatabase.&nbsp;<\/p>\n\n\n\n<p>A special note: The current version of GeoTools requires Java 11.<\/p>\n\n\n\n<p>In the Feature Tutorial, you will gain more understanding of shapefiles by making shapefiles from a CSV file. Each item in the shape is called a &#8220;feature&#8221;.&nbsp; The feature has a &#8220;geometry&#8221; and associated properties.&nbsp;<\/p>\n\n\n\n<p>In the Query Tutorial, you learn how to make queries into the Shapefile. Rather you make queries into the datastore that you build from the shapefiles. The queries can be geographical such as does a feature contain a point. Although relational databases use SQL, the Query Tutorial uses the Common Query Language, CQL.&nbsp;<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">The Challenge<\/h1>\n\n\n\n<p>After completing the three tutorials, you should realize that there are still some challenges for using GeoTools in a Grails app.&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GeoTools uses Maven for the build while Grails uses Gradle.&nbsp;<\/li>\n\n\n\n<li>How to organize GeoTools code so the Grails controllers have easy access to its functions.<\/li>\n<\/ul>\n\n\n\n<p>The first project in this lecture demonstrates how to build a GeoTools app using Gradle. It is not a difficult challenge, but requires knowledge of both Maven and Gradle. The app is simple. It reads a shapefile, builds a datastore and then query it.&nbsp;<\/p>\n\n\n\n<p>The best way for Grails controllers to access datastores is from a service. But we don&#8217;t want each query into the datastore to reread and load the shapefile. So our program should create a Java object representing the datastore. But this leads to another problem, how should the Service access the datastore object? The technology to use is called &#8220;Spring Beans&#8221;. The second project in this lecture will briefly explain the Spring Bean technology and how to use them in a Grails app.<\/p>\n\n\n\n<p>The final project in this lecture combines the two previous projects to render geographical information in a view. A bean will represent the datastore built from the shapefiles and a service will make queries into the feature sources.&nbsp;<\/p>\n\n\n\n<p>You can clone the code at:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/2024-UI-SP\/GeoTools-Lecture\">https:\/\/github.com\/2024-UI-SP\/GeoTools-Lecture<\/a><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">gradle-geotools<\/h1>\n\n\n\n<p>The gradle-geotools project demonstrates developing a simple GeoTools app in a Gradle project. It was initialized in the gradle-geotools directory with Gradle 7.2 using Java 11. We make the basic Gradle project by&nbsp; entering<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">gradle init<\/pre>\n\n\n\n<p>The script will ask questions about the project:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Select type of build to generate:<\/strong> selected 2. application<\/li>\n\n\n\n<li><strong>Select implementation language:<\/strong> selected 3. java (default)<\/li>\n\n\n\n<li><strong>Split functionality across multiple subprojects?:<\/strong> selected 1 no (default)<\/li>\n\n\n\n<li><strong>Select build script DSL:<\/strong> selected 1 Groovy (default)<\/li>\n\n\n\n<li><strong>Select test framework:<\/strong> 1. JUint 4<\/li>\n\n\n\n<li><strong>Project name (default: gradle-geotools):<\/strong><\/li>\n\n\n\n<li><strong>Source package (default: gradle.geotools):<\/strong><\/li>\n<\/ul>\n\n\n\n<p>The script makes a &#8220;hello world&#8221; app. The code for the class is located in <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">app\/src\/main\/gradle\/geotools\/App.java<\/code>. You can run the &#8220;hello world&#8221; app by entering<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">.\/gradlew run<\/pre>\n\n\n\n<p>To make the project we only need to&nbsp;<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Edit<code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\"> app\/src\/main\/java\/gradle\/geotools\/App.java<\/code><\/li>\n\n\n\n<li>Put the shapefiles in <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">app\/src\/main\/resources\/gradle\/geotools\/<\/code><\/li>\n\n\n\n<li>Edit <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">app\/build.gradle<\/code><\/li>\n<\/ol>\n\n\n\n<p>First, we edit <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">app\/src\/main\/java\/gradle\/geotools\/App.java<\/code>. We replace the code with:&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/*\n * This Java source file was generated by the Gradle 'init' task.\n *\/\npackage gradle.geotools;\n\n\/\/ The following imports are for working with files\nimport java.io.File;\nimport java.net.URL;\n\n\/\/ The following imports are for making the data store and source\nimport org.geotools.api.data.FileDataStore;\nimport org.geotools.api.data.FileDataStoreFinder;\nimport org.geotools.api.data.SimpleFeatureSource;\n\n\/\/ The following imports are for making the query\nimport org.geotools.filter.text.cql2.CQL; \/\/ this needs gt-swing dependency\n\nimport org.geotools.api.filter.Filter;\n\nimport org.geotools.data.simple.SimpleFeatureCollection;\nimport org.geotools.data.simple.SimpleFeatureIterator;\nimport org.geotools.api.feature.simple.SimpleFeature;\nimport org.geotools.api.feature.type.FeatureType;\n\nimport org.geotools.api.data.Query;\n\npublic class App {\n\n    public static void main(String[] args) throws Exception {\n        System.out.println(\"Running App.main() \\n\");\n\n        \/*\n         * Make the data store and feature source\n         *\/\n        \/\/ Get the shapefile using getResource()\n        URL url = App.class.getResource(\"countries.shp\");\n        \/\/ Just to make sure we got the right file\n        System.out.println(\"URL: \" + url+ \"\\n\");  \n        File file = new File(url.toURI());\n\n        \/\/ Use the file to make the data store using FileDataStoreFinder\n        FileDataStore store = FileDataStoreFinder.getDataStore(file);\n        \/\/ Get the feature source from the store using getFeatureSource()\n        SimpleFeatureSource source = store.getFeatureSource();\n\n        \/\/ Do some printing      \n        String typeName = store.getTypeNames()[0]; \/\/ There is only one type\n        System.out.println(\"typeName is the name of datastore. It is almost always the name of the shapefile.\");\n        System.out.println(\"typeName: \" + typeName + \"\\n\");\n        FeatureType schema = source.getSchema();\n        System.out.println(\"schema is the list of shapefile's attributes and types\");\n        System.out.println(\"schema: \" + schema + \"\\n\");\n       \n        \/*\n         * Make the query and filter to show all countries and population\n         *\/\n        System.out.println(\"Result from querying for all countries and population\");\n        String cqlString = \"include\"; \/\/ Include all features\n        Filter filter = CQL.toFilter(cqlString);\n        Query query = new Query(typeName, filter, new String[] { \"CNTRY_NAME\", \"POP_CNTRY\" });\n        System.out.println(\"query: \" + query + \"\\n\");\n\n        \/\/ Get the features, i.e. the \"result set\"\n        SimpleFeatureCollection features = source.getFeatures(query);\n\n        try (SimpleFeatureIterator iterator = features.features()) {\n            while (iterator.hasNext()) {\n                SimpleFeature feature = iterator.next();\n                \/\/ process feature\n                for ( Object value : feature.getAttributes() ) {\n                    System.out.print(value + \" \");\n                }\n                System.out.println();\n            }\n        }\n        System.out.println(\" \\n \");\n\n        \/*\n         * Make the query and filter to find the country that contains the a point.\n         *\/\n        System.out.println(\"Result from querying for the country that contains a point\");\n        filter = CQL.toFilter(\"contains(the_geom, POINT(-100 40))\"); \/\/ Note logitude first\n        query = new Query(typeName, filter, new String[] { \"CNTRY_NAME\", \"POP_CNTRY\" });\n        System.out.println(\"query: \" + query + \"\\n\");\n\n        \/\/ process the features. All this for a single item because features is a collection\n        features = source.getFeatures(query);\n        try (SimpleFeatureIterator iterator = features.features()) {\n            while (iterator.hasNext()) {\n                SimpleFeature feature = iterator.next();\n                for ( Object value : feature.getAttributes() ) {\n                    System.out.print(value + \" \");\n                }\n                System.out.println();\n            }\n        }\n        System.out.println(\" \\n \");\n    }  \n}\n<\/pre>\n\n\n\n<p>The code is the simplest code that I could write to load a shapefile to create the datastore, make a few queries into the feature source, and process the feature collection resulting from the queries<\/p>\n\n\n\n<p>Note the Java File is made using <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">class.getResources<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">       URL url = App.class.getResource(\"countries.shp\");\n       \/\/ Just to make sure we got the right file\n       System.out.println(\"URL: \" + url+ \"\\n\");  \n       File file = new File(url.toURI());\n<\/pre>\n\n\n\n<p><a href=\"https:\/\/docs.oracle.com\/javase\/6\/docs\/api\/java\/lang\/Class.html#getResource(java.lang.String)\">https:\/\/docs.oracle.com\/javase\/6\/docs\/api\/java\/lang\/Class.html#getResource(java.lang.String)<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/stackoverflow.com\/questions\/6608795\/what-is-the-difference-between-class-getresource-and-classloader-getresource\">https:\/\/stackoverflow.com\/questions\/6608795\/what-is-the-difference-between-class-getresource-and-classloader-getresource<\/a><\/p>\n\n\n\n<p>Now we add the shapefiles. Conveniently, the initializing script made a resources directory in app\/src\/main\/. But we need the path to match the class package, so we make <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">app\/src\/main\/resources\/gradle\/geotools\/shapefiles<\/code>, and put the shapefiles in the shapefiles directory. The countries shapefiles are from <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">data-v1_2.zip<\/code>. You can find the zip file at:<\/p>\n\n\n\n<p><a href=\"http:\/\/udig.refractions.net\/files\/docs\/\">http:\/\/udig.refractions.net\/files\/docs\/<\/a><\/p>\n\n\n\n<p>Note you should use the code from the Query Tutorial to examine the shapefiles and learn the property names.&nbsp;<\/p>\n\n\n\n<p>The code uses a CQL string to make the filter. Because we want only a few properties of the features, we need to construct a <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">Query<\/code>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">        System.out.println(\"Result from querying for all countries and population\");\n        String cqlString = \"include\"; \/\/ Include all features\n        Filter filter = CQL.toFilter(cqlString);\n        Query query = new Query(typeName, filter, new String[] { \"CNTRY_NAME\", \"POP_CNTRY\" });\n        System.out.println(\"query: \" + query + \"\\n\");\n<\/pre>\n\n\n\n<p>To examine the feature collection from the result of the query, the code MUST use <strong><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">try<\/code><\/strong> and the iterator:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">       try (SimpleFeatureIterator iterator = features.features()) {\n            while (iterator.hasNext()) {\n            ...\n            }\n        }<\/pre>\n\n\n\n<p>To summarize, the code needs to:&nbsp;<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Make the SimpleFileDataStore using a FileDataStoreFinder with a File<\/li>\n\n\n\n<li>Get the SimpleDataFeatureSource&nbsp;<\/li>\n\n\n\n<li>Make the Query with a Filter using a CQL string<\/li>\n\n\n\n<li>Get the &#8220;results set&#8221; as a SimpleFeatureCollection<\/li>\n\n\n\n<li>try to iterate through the SimpleFeatures using SimpleFeatureIterator<\/li>\n<\/ol>\n\n\n\n<p>Finally to build the project, we need to edit <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">build.gradle<\/code>. The GeoTools jars are not located in Maven Central, rather they are located at OSGeo repositories, so we need to add them to the repositories section of build.gradle.&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    maven {\n        url \"https:\/\/repo.osgeo.org\/repository\/snapshot\/\"\n        mavenContent {\n            snapshotsOnly()\n        }  \n    }\n\n    maven {\n         url \"https:\/\/repo.osgeo.org\/repository\/release\/\"\n         mavenContent {\n             releasesOnly()\n         }\n    }<\/pre>\n\n\n\n<p>I determined these unusual declarations from&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<p><a href=\"https:\/\/docs.gradle.org\/current\/userguide\/declaring_repositories.html#maven_repository_filtering\">https:\/\/docs.gradle.org\/current\/userguide\/declaring_repositories.html#maven_repository_filtering<\/a><\/p>\n\n\n\n<p>and inspecting the mvn declarations in the GeoTools tutorials. Also important is that these declarations must be placed before the maven central declaration because the javax.mediajai_core POM is broken in maven central. Gradle searches the repositories in order so if maven central is searched first. It discovers the POM for the package, but the package does not exist. This brakes Maven and Gradle.&nbsp;&nbsp;<\/p>\n\n\n\n<p><a href=\"https:\/\/stackoverflow.com\/questions\/26993105\/i-get-an-error-downloading-javax-media-jai-core1-1-3-from-maven-central\">https:\/\/stackoverflow.com\/questions\/26993105\/i-get-an-error-downloading-javax-media-jai-core1-1-3-from-maven-central<\/a><\/p>\n\n\n\n<p>Now add the project dependencies in the dependencies section<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    String geotoolsVersion = '32-SNAPSHOT'\n    \/\/ Provides support for reading and writing shapefiles\n    \/\/ Needed to make the data store\n    implementation \"org.geotools:gt-shapefile:$geotoolsVersion\"\n\n    \/\/ Needed for CQL filters\n    implementation \"org.geotools:gt-swing:$geotoolsVersion\"<\/pre>\n\n\n\n<p>Most of the classes used by<code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\"> App.java<\/code> are found in the gt-shapefile package. The gt-swing package is only required for <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">org.geotools.filter.text.cql2.CQL<\/code>. Otherwise gt-swing contains classes for building GUIs.&nbsp;<\/p>\n\n\n\n<p>We are done and can run the project with<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">.\/gradlew run<\/pre>\n\n\n\n<p>Look for the print output in the console. Study the code. Try writing a different query and processing the resulting feature collection.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">grails-beans<\/h1>\n\n\n\n<p>This project demonstrates how Spring Beans are used in a Grails project. The bean only prints out to the terminal. We want to learn:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>where the beans are defined&nbsp;<\/li>\n\n\n\n<li>how they are integrated in the Grails project<\/li>\n\n\n\n<li>how they can be used in the project, i.e. injected<\/li>\n<\/ul>\n\n\n\n<p>The Grails documentation for Spring Beans does not explain how to define and use beans.<\/p>\n\n\n\n<p><a href=\"https:\/\/docs.grails.org\/6.2.0\/guide\/single.html#spring\">https:\/\/docs.grails.org\/6.2.0\/guide\/single.html#spring<\/a><\/p>\n\n\n\n<p>We have to study the Spring documentation to learn more about beans:&nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<p><a href=\"https:\/\/docs.spring.io\/spring-framework\/reference\/core\/beans\/introduction.html\">https:\/\/docs.spring.io\/spring-framework\/reference\/core\/beans\/introduction.html<\/a><\/p>\n\n\n\n<p>You will want to read more:&nbsp;<\/p>\n\n\n\n<p><a href=\"https:\/\/docs.spring.io\/spring-framework\/reference\/core\/beans\/basics.html\">https:\/\/docs.spring.io\/spring-framework\/reference\/core\/beans\/basics.html<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/docs.spring.io\/spring-framework\/reference\/core\/beans\/definition.html\">https:\/\/docs.spring.io\/spring-framework\/reference\/core\/beans\/definition.html<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/docs.spring.io\/spring-framework\/reference\/core\/beans\/factory-scopes.html\">https:\/\/docs.spring.io\/spring-framework\/reference\/core\/beans\/factory-scopes.html<\/a><\/p>\n\n\n\n<p>If the Spring documentation is too technical, you may find this stackoverflow post more gentle.<\/p>\n\n\n\n<p><a href=\"https:\/\/stackoverflow.com\/questions\/17193365\/what-in-the-world-are-spring-beans\">https:\/\/stackoverflow.com\/questions\/17193365\/what-in-the-world-are-spring-beans<\/a><\/p>\n\n\n\n<p>The basic goal for the bean framework is that the developer should not have to worry about managing when and how to instantiate simple Java objects (called beans)&nbsp; and other classes in&nbsp; the application have access to the beans. Rather the &#8220;container&#8221; manages instantiating beans and making easy access to the instantiated bean for the other classes in the application.&nbsp; For this to happen properly, naturally, the developer needs to configure and register the bean with the &#8220;container&#8221;. Configuration includes:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The name of the bean (called the id in Spring)<\/li>\n\n\n\n<li>The class defining the bean<\/li>\n\n\n\n<li>The scope of the bean, e.g. singleton, session, request etc. Note singleton is default scope&nbsp;<\/li>\n\n\n\n<li>other optional properties of the bean<\/li>\n<\/ul>\n\n\n\n<p>Traditionally Spring used XML in a resources\/spring.xml file to configure the bean. Grails uses Groovy to configure beans in the <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">conf\/spring\/resources.groovy<\/code><\/p>\n\n\n\n<p>You should realize that in a Grails project almost all groovy classes are beans, this includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Domains<\/li>\n\n\n\n<li>Controllers<\/li>\n\n\n\n<li>Services<\/li>\n\n\n\n<li>BootStrap.groovy<\/li>\n<\/ul>\n\n\n\n<p>Grails manages configuration of these beans.<\/p>\n\n\n\n<p>Now we can look at the code. The basic Grail app was made with Grails 5.3 and Java 11 by entering<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">grails create-app grails-bean<\/pre>\n\n\n\n<p>This creates a simple web app using the grails.bean package name.<\/p>\n\n\n\n<p>First we will study a simple bean. The class files that you make yourself are located in src\/main\/groovy followed by the package directories. In this case<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">src\/main\/groovy\/grails\/bean\/MyBean.groovy<\/pre>\n\n\n\n<p>where &#8220;grails\/bean\/&#8221; is the package directory.&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package grails.bean \/\/ Don't forget!\n\n\/*\n * A simple bean to demonstrate instantiation, injection and use in Grails.\n * See conf\/spring\/resources.groovy for instantiation.\n * See BootStrap.groovy for injection and use.\n *\/\nclass MyBean {\n    String name\n    private String constructorName\n\n    MyBean(String constructorName) {\n        println \"In MyBean constructor\"\n        this.constructorName = constructorName\n    }\n\n    void printName() {\n        println \"MyBean name: ${name}\"\n    }\n\n    void printConstructorName() {\n        println \"MyBean constructorName: ${constructorName}\"\n    }\n}<\/pre>\n\n\n\n<p>This bean has only two attributes, <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">name<\/code> and <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">constructorName<\/code>, and two methods to print the attributes. Note that <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">constructorName<\/code> attribute is set by the constructor, while the <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">name<\/code> attribute is public, so can be set by anyone.&nbsp;<\/p>\n\n\n\n<p>After writing the bean definition, you can run the application, but nothing will happen, although it will be compiled.&nbsp;<\/p>\n\n\n\n<p>To instantiate bean, we need to configure and register it in <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">grails-app\/conf\/spring\/resource.groovy<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import grails.bean.MyBean\n\n\/*\n * beans registers and instantiates beans.\n * See https:\/\/docs.grails.org\/6.2.0\/guide\/spring.html for simple examples.\n * See https:\/\/stackoverflow.com\/questions\/22400078\/inject-constructor-argument-spring-resource-file-with-grails-groovy\n * for how to inject constructor arguments.\n *\/\n\nbeans = {\n    \/\/ This closure uses Spring Domain Specific Language (DSL).\n    \/\/ The first argument is the class name and following argument are the constructor arguments\n    myBean(MyBean, \"My_Bean_Constructor\") {\n        \/\/ Here public variables are set\n        name = \"My_Bean\"\n    }\n}<\/pre>\n\n\n\n<p>What looks like a &#8220;method call&#8221; names the bean, <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">myBean<\/code>. This is what other classes use to reference the bean. The minimal declaration for a bean is<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package &lt;package> &lt;Bean class>\n\nbeans = {\n&lt;bean id>(&lt;Bean class>)\n}<\/pre>\n\n\n\n<p>This will name a singleton bean and instantiate it using the default constructor (i.e. with on arguments). In the method body, you can define public attributes. If the constructor has arguments then they are listed after the class in the bean declaration.&nbsp;<\/p>\n\n\n\n<p><a href=\"https:\/\/stackoverflow.com\/questions\/22400078\/inject-constructor-argument-spring-resource-file-with-grails-groovy\">https:\/\/stackoverflow.com\/questions\/22400078\/inject-constructor-argument-spring-resource-file-with-grails-groovy<\/a><\/p>\n\n\n\n<p>You can run the code now, and notice that Grails instantiate the bean because the constructor prints.&nbsp;<\/p>\n\n\n\n<p>Now to use the bean by calling its method. We could use the bean in almost any other part of the application. BootStrap.groovy runs before any other Grails artifacts, so we use it there.&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package grails.bean\n\nclass BootStrap {\n    def myBean \/\/ This is injecting myBean\n\n    def init = { servletContext ->    \n        println \"In BootStrap init\"\n        \/*\n         * Demonstrates how to use a bean in Grails by calling methods.\n         *\/\n        myBean.printConstructorName()\n        myBean.printName()\n        println \"\\n\"\n    }\n    def destroy = {\n    }\n}<\/pre>\n\n\n\n<p>To inject the bean, all we need to do is declare the bean&#8217;s name as a class attribute<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def myBean<\/pre>\n\n\n\n<p>That is it. Running the Grails app now will make all the print outs.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">.\/gradlew bootRun<\/pre>\n\n\n\n<p>Very cool! Try making your own bean.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">grails-geotools<\/h1>\n\n\n\n<p>We have learned all the technologies for integrating GeoTools into a Grails app. First we should think about how to architect the code. Best practice is that controllers use services to access datastores. But we do not want the service to be creating the datastore for every call, so we should use a singleton bean to represent the datastore. The constructor for the bean can create the datastore. So the architecture is<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">MyFeatureSouce.groovy<\/code> &#8211; a bean that creates the datastore, specifically a <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">SimpleFeatureSource<\/code>, and offer access to the datastore<\/li>\n\n\n\n<li><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">FeatureService.groovy<\/code> &#8211; a service with reference to <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">myFeatureSource<\/code> and has a method to make the <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">Query <\/code>and process the <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">SimpleFeatures <\/code>from&nbsp; the <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">SimpleFeatureCollection<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>The FeatureService will return the country name for a latitude, longitude. Finally we want to render the service in a controller, <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">CountryController.groovy<\/code>.<\/p>\n\n\n\n<p>Now we can look at the project code. The project was made using Grails 5.3 and Java 11, and entering&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">.\/grails create-app grails-geotools<\/pre>\n\n\n\n<p>which makes a web application with the package name &#8220;grails.geotools&#8221;.&nbsp;<\/p>\n\n\n\n<p>First we edit the build.gradle, the repositories and dependencies. This is identical to the gradle-geotools, so I&#8217;ll not display it again.&nbsp;<\/p>\n\n\n\n<p>Now make our bean, <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">MyFeatureSource.groovy<\/code>, in <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">src\/main\/groovy\/grails\/geotools\/<\/code>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package grails.geotools\n\n\/\/ For working with files\nimport java.io.File\nimport java.net.URL\n\n\/\/ For making the data store and source\nimport org.geotools.api.data.FileDataStore\nimport org.geotools.api.data.FileDataStoreFinder\nimport org.geotools.api.data.SimpleFeatureSource\n\n\/*\n * A bean generating a SimpleFeatureSource from a shapefile.\n * See conf\/spring\/resources.groovy for registrating.\n * See BootStrap.groovy and CountryController for use.\n *\/\nclass MyFeatureSource {\n    private String shapefileName\n    private SimpleFeatureSource source\n\n    MyFeatureSource(String shapefileName) {\n        this.shapefileName = shapefileName  \n        println \"\\n\"    \n        println \"In MyFeatureSource constructor\"\n\n        \/\/ Make File\n        URL url = MyFeatureSource.class.getResource(\"shapefiles\/${shapefileName}\")\n        File file = new File(url.toURI())\n        println(\"File: \" + file)\n\n        \/\/ Make DataStore\n        FileDataStore store = FileDataStoreFinder.getDataStore(file)\n        println(\"Type Names: \" + store.getTypeNames())\n        source = store.getFeatureSource()\n    }\n\n    \/\/ Just for development\n    void printHi() {\n        println \"\\n\"\n        println \"Hi from MyFeatureSource!\"\n        println \"MyFeatureSource shapefileName: ${shapefileName}\"\n    }\n\n    SimpleFeatureSource getSource() {\n        return source\n    }\n}<\/pre>\n\n\n\n<p>Given a shapefile name the constructor makes the SimpleFeatureSource, <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">source<\/code>. There is only one method, <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">getSource <\/code>which the service will use. The code should look familiar.&nbsp;<\/p>\n\n\n\n<p>We put the shapefiles in <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">src\/main\/resources\/grails\/geotools\/shapefiles\/<\/code><\/p>\n\n\n\n<p>Now, we register the bean in <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">spring\/resources.groovy<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import grails.geotools.MyFeatureSource\n\n\/*\n * beans resigisters and instantiates beans.\n * See https:\/\/docs.grails.org\/6.2.0\/guide\/spring.html for simple examples.\n * See https:\/\/stackoverflow.com\/questions\/22400078\/inject-constructor-argument-spring-resource-file-with-grails-groovy\n * for how to inject constructor arguments.\n *\/\nbeans = {\n    \/\/ The first argument is the constructor, the second is the argument.\n    myFeatureSource(MyFeatureSource, \"countries.shp\")\n}<\/pre>\n\n\n\n<p>Next, we make the service, <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">FeatureService.groovy<\/code>, by entering<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">.\/grailsw create-service grails.geotools.FeatureService<\/pre>\n\n\n\n<p><a href=\"https:\/\/docs.grails.org\/6.2.0\/ref\/Command%20Line\/create-service.html\">https:\/\/docs.grails.org\/6.2.0\/ref\/Command%20Line\/create-service.html<\/a><\/p>\n\n\n\n<p>We edit <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">FeatureService.groovy<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package grails.geotools\n\n\/\/ For Query\nimport org.geotools.filter.text.cql2.CQL\nimport org.geotools.api.data.Query\nimport org.geotools.api.filter.Filter\n\n\/\/ For Features\nimport org.geotools.data.simple.SimpleFeatureCollection\nimport org.geotools.data.simple.SimpleFeatureIterator\nimport org.geotools.api.feature.simple.SimpleFeature\n\nimport grails.gorm.transactions.Transactional\n\n@Transactional\nclass FeatureService {\n    \/\/ FeatureService needs a FeatureSource\n    def myFeatureSource \/\/ from src\/main\/groovy\/geotools\/MyFeatureSource.groovy\n\n    def getCountryName(double latitude, double longitude) {\n        println \"\\n\"\n        println \"In FeatureService getCountryName\"\n        \/\/ Get Source      \n        def source = myFeatureSource.getSource()\n\n        \/\/ Make Query\n        String filterString = \"contains(the_geom, POINT(${longitude} ${latitude}))\"\n        Filter filter = CQL.toFilter(filterString)\n        String typeName = source.getSchema().getTypeName()\n        String [] propertyNames = new String[] { \"CNTRY_NAME\" }\n        Query query = new Query(typeName, filter, propertyNames)\n\n        \/\/ Get Features and Collect Country Names\n        SimpleFeatureCollection features = source.getFeatures(query)\n        def countryNames = []\n        try (SimpleFeatureIterator iterator = features.features()) {\n            while (iterator.hasNext()) {\n                SimpleFeature feature = iterator.next()\n                println \"Feature: ${feature}\"\n                println \"Feature Attribute CNTRY_NAME: ${feature.getAttribute(\"CNTRY_NAME\")}\"\n\n\n                countryNames &lt;&lt; feature.getAttribute(\"CNTRY_NAME\")\n            }\n        }\n        return countryNames\n    }\n}<\/pre>\n\n\n\n<p>FeatureService has an attribute referencing myFeautureSource, so the bean will be injected. There is only one method, <code data-enlighter-language=\"groovy\" class=\"EnlighterJSRAW\">getCountryName(double latitude, double longitude)<\/code>. The code in the method body should be familiar.&nbsp;<\/p>\n\n\n\n<p>I used Bootstrap.groovy during development to assure that the bean and services were made properly.<\/p>\n\n\n\n<p>We make the controller by entering<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">.\/grailsw create-controller Country<\/pre>\n\n\n\n<p>Finally, we edit <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">CountryController.groovy<\/code>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package grails.geotools\n\/*\n * A controller demonstrating FeatureService.\n * See grails-app\/services\/geotools\/FeatureService.groovy for the service.\n *\/\nclass CountryController {\n    \/\/ Inject FeatureService\n    def featureService\n\n    def index() {\n        \/\/ Use FeatureService\n        double latitude = 38.0\n        double longitude = -77.0\n        def countryNames = featureService.getCountryName(latitude, longitude)\n\n\n        \/\/ render the view\n        render \"In CountryController: Country Names: ${countryNames}\"\n    }\n}<\/pre>\n\n\n\n<p>Very simple, we don&#8217;t even need to make the index view.&nbsp;<\/p>\n\n\n\n<p>You can run the app<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">.\/gradle bootRun<\/pre>\n\n\n\n<p>and open the browser to localhost:8080\/country<\/p>\n\n\n\n<p>That is it. The hard part was figuring out how to use Gradle to make a GeoTools app and how to use Spring Beans in Grails.<\/p>\n\n\n\n<p>To summarize to use GeoTools in a Grails app, you should<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Edit build.gradle, adding the repositories and dependencies.<\/li>\n\n\n\n<li>Make a bean for the datastore<\/li>\n\n\n\n<li>Register the bean<\/li>\n\n\n\n<li>Make a service to query using the bean<\/li>\n\n\n\n<li>Use the service in a controller to render the results in a view.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>GeoTools is an open source Java library for authoring GIS software and applications.&nbsp; https:\/\/geotools.org It is a fully equipped library adhering to the Open Geospatial Consortium (OGC) standards and providing graphical user interface (GUI).&nbsp; https:\/\/docs.geotools.org\/latest\/userguide\/welcome\/standards.html This lecture demonstrates techniques for using GeoTools in a Grails app through the sequence of three projects: The final project, [&hellip;]<\/p>\n","protected":false},"author":62,"featured_media":0,"parent":112,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-4016","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/pages\/4016","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/users\/62"}],"replies":[{"embeddable":true,"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/comments?post=4016"}],"version-history":[{"count":10,"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/pages\/4016\/revisions"}],"predecessor-version":[{"id":4169,"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/pages\/4016\/revisions\/4169"}],"up":[{"embeddable":true,"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/pages\/112"}],"wp:attachment":[{"href":"https:\/\/cs4760.csl.mtu.edu\/2025\/wp-json\/wp\/v2\/media?parent=4016"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}