diff --git a/simpleexample/src/main/java/simpleex/core/LatLong.java b/simpleexample/src/main/java/simpleex/core/LatLong.java
index 68d10a1f3614a1eb6e74cdd4ef5383f46e84aec7..02322b855c99bb8d603bbdc38dbf2f8600a828c3 100644
--- a/simpleexample/src/main/java/simpleex/core/LatLong.java
+++ b/simpleexample/src/main/java/simpleex/core/LatLong.java
@@ -1,5 +1,10 @@
 package simpleex.core;
 
+/**
+ * Represents a geo-location as a latitude, longitude pair.
+ * @author hal
+ *
+ */
 public class LatLong {
 
   public static final String SEPARATOR = ",";
@@ -7,16 +12,29 @@ public class LatLong {
   private final double latitude;
   private final double longitude;
 
+  /**
+   * Initialize a LatLong with provided latitude and longitude.
+   * @param latitude the latitude
+   * @param longitude the longitude
+   */
   public LatLong(final double latitude, final double longitude) {
     super();
     this.latitude = latitude;
     this.longitude = longitude;
   }
 
+  /**
+   * Gets the latitude.
+   * @return the latitude
+   */
   public double getLatitude() {
     return latitude;
   }
 
+  /**
+   * Gets the longitude.
+   * @return the longitude
+   */
   public double getLongitude() {
     return longitude;
   }
@@ -49,10 +67,23 @@ public class LatLong {
         && Double.doubleToLongBits(longitude) == Double.doubleToLongBits(other.longitude));
   }
 
+  /**
+   * Creates a LatLong object from a String.
+   * The format is <latitude>,<longitude>.
+   * @param s the String to parse
+   * @return the new LatLong object
+   */
   public static LatLong valueOf(final String s) {
     return valueOf(s, SEPARATOR);
   }
 
+  /**
+   * Creates a LatLong object from a String, using a specific separator.
+   * The format is <latitude><separator><longitude>.
+   * @param s
+   * @param sep
+   * @return
+   */
   public static LatLong valueOf(final String s, final String sep) {
     final int pos = s.indexOf(sep);
     if (pos < 0) {
@@ -103,10 +134,21 @@ public class LatLong {
     return dist;
   }
 
+  /**
+   * Computes the distance in meters between two LatLong objects.
+   * @param latLong1 the first LatLong
+   * @param latLong2 the other LatLong
+   * @return the distance in meters
+   */
   public static double distance(final LatLong latLong1, final LatLong latLong2) {
     return distance(latLong1.latitude, latLong1.longitude, latLong2.latitude, latLong2.longitude);
   }
 
+  /**
+   * Computes the distance in meters between this LatLong and an other one.
+   * @param latLong2 the other LatLong
+   * @return the distance in meters
+   */
   public double distance(final LatLong latLong2) {
     return distance(latitude, longitude, latLong2.latitude, latLong2.longitude);
   }
diff --git a/simpleexample2/build.gradle b/simpleexample2/build.gradle
index cda0331a2f73d475b5b7b61640fe082d65135feb..07f8ceb256f4576ca22f5739f7f4a40ce52e2ce9 100644
--- a/simpleexample2/build.gradle
+++ b/simpleexample2/build.gradle
@@ -6,3 +6,7 @@ allprojects {
         }
     }
 }
+
+subprojects {
+    ext.depVersions = ['jackson': '2.9.8']
+}
diff --git a/simpleexample2/core/README.md b/simpleexample2/core/README.md
index 9500dc502cb161d2fac70b85f1c1168bb7814ff9..4af7ab49f6eb78bdc4b50e2d7e3da1ba67827c9b 100644
--- a/simpleexample2/core/README.md
+++ b/simpleexample2/core/README.md
@@ -2,15 +2,6 @@
 
 Dette prosjektet inneholder domene- og persistenslagene for [simpleexample2](../README.md).
 
-## Organisering av koden
-
-Prosjektet er organisert med 2 * 2 = 4 kildekodemapper, kode og ressurser for henholdsvis applikasjonen selv og testene:
-
-- **src/main/java** for koden til applikasjonen
-- **src/main/resources** for tilhørende ressurser, f.eks. data-filer, som brukes av applikasjonen.
-- **src/test/java** for testkoden
-- **src/test/resources** for tilhørende ressurser, f.eks. data-filer, som brukes av testene.
-
 ## Domenelaget
 
 Domenelaget inneholder alle klasser og logikk knyttet til dataene som applikasjonen handler om og håndterer. Dette laget skal være helt uavhengig av brukergrensesnittet eller lagingsteknikken som brukes.
diff --git a/simpleexample2/core/build.gradle b/simpleexample2/core/build.gradle
index 0bc50ccc896ef7bbb1e4a95ce221151b50752061..54e731579449acf93bc9f6939093b076d041bf88 100644
--- a/simpleexample2/core/build.gradle
+++ b/simpleexample2/core/build.gradle
@@ -42,7 +42,7 @@ checkstyle {
 dependencies {
 	// persistens
 	// api means that those consuming our library 'inherits' this as a compile dependency
-    api 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
+    api "com.fasterxml.jackson.core:jackson-databind:${depVersions.jackson}"
 
     // Use JUnit test framework
     testImplementation 'junit:junit:4.12'
diff --git a/simpleexample2/core/src/main/java/core/Library.java b/simpleexample2/core/src/main/java/core/Library.java
deleted file mode 100644
index 2d14c4b1720efc1e1e07dd794a261d591fa398c4..0000000000000000000000000000000000000000
--- a/simpleexample2/core/src/main/java/core/Library.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * This Java source file was generated by the Gradle 'init' task.
- */
-package core;
-
-public class Library {
-    public boolean someLibraryMethod() {
-        return true;
-    }
-}
diff --git a/simpleexample2/core/src/main/java/simpleex/core/LatLong.java b/simpleexample2/core/src/main/java/simpleex/core/LatLong.java
index 68d10a1f3614a1eb6e74cdd4ef5383f46e84aec7..36f118497df7fffb33cafd90f8c7308237b9b78e 100644
--- a/simpleexample2/core/src/main/java/simpleex/core/LatLong.java
+++ b/simpleexample2/core/src/main/java/simpleex/core/LatLong.java
@@ -1,22 +1,43 @@
 package simpleex.core;
 
+/**
+ * Represents a geo-location as a latitude, longitude pair.
+ * @author hal
+ *
+ */
 public class LatLong {
 
+  /**
+   * The default separator for the valueOf method.
+   */
   public static final String SEPARATOR = ",";
 
   private final double latitude;
   private final double longitude;
 
+  /**
+   * Initialize a LatLong with provided latitude and longitude.
+   * @param latitude the latitude
+   * @param longitude the longitude
+   */
   public LatLong(final double latitude, final double longitude) {
     super();
     this.latitude = latitude;
     this.longitude = longitude;
   }
 
+  /**
+   * Gets the latitude.
+   * @return the latitude
+   */
   public double getLatitude() {
     return latitude;
   }
 
+  /**
+   * Gets the longitude.
+   * @return the longitude
+   */
   public double getLongitude() {
     return longitude;
   }
@@ -49,10 +70,23 @@ public class LatLong {
         && Double.doubleToLongBits(longitude) == Double.doubleToLongBits(other.longitude));
   }
 
+  /**
+   * Creates a LatLong object from a String.
+   * The format is &lt;latitude&gt;,&lt;longitude&gt;.
+   * @param s the String to parse
+   * @return the new LatLong object
+   */
   public static LatLong valueOf(final String s) {
     return valueOf(s, SEPARATOR);
   }
 
+  /**
+   * Creates a LatLong object from a String, using a specific separator.
+   * The format is &lt;latitude&gt;&lt;separator&gt;&lt;longitude&gt;.
+   * @param s the String to parse
+   * @param sep the separator
+   * @return the new LatLong object
+   */
   public static LatLong valueOf(final String s, final String sep) {
     final int pos = s.indexOf(sep);
     if (pos < 0) {
@@ -64,28 +98,32 @@ public class LatLong {
     return new LatLong(lat, lon);
   }
 
-  /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */
-  /* :: : */
-  /* :: This routine calculates the distance between two points (given the : */
-  /* :: latitude/longitude of those points). It is being used to calculate : */
-  /* :: the distance between two locations using GeoDataSource (TM) products : */
-  /* :: : */
-  /* :: Definitions: : */
-  /* :: South latitudes are negative, east longitudes are positive : */
-  /* :: : */
-  /* :: Passed to function: : */
-  /* :: lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees) : */
-  /* :: lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees) : */
-  /* :: Worldwide cities and other features databases with latitude longitude : */
-  /* :: are available at http://www.geodatasource.com : */
-  /* :: : */
-  /* :: For enquiries, please contact sales@geodatasource.com : */
-  /* :: : */
-  /* :: Official Web site: http://www.geodatasource.com : */
-  /* :: : */
-  /* :: GeoDataSource.com (C) All Rights Reserved 2015 : */
-  /* :: : */
-  /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */
+  /**
+   * This routine calculates the distance between two points (given the
+   * latitude/longitude of those points). It is being used to calculate
+   * the distance between two locations using GeoDataSource (TM) products
+   *
+   * <p>Definitions:
+   * South latitudes are negative, east longitudes are positive
+   *
+   * <p>Passed to function:
+   * lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees)
+   * lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees)
+   * Worldwide cities and other features databases with latitude longitude
+   * are available at http://www.geodatasource.com
+   *
+   * <p>For enquiries, please contact sales@geodatasource.com
+   *
+   * <p>Official Web site: http://www.geodatasource.com
+   *
+   * <p>GeoDataSource.com (C) All Rights Reserved 2015
+   *
+   * @param lat1 the latitude of the first point
+   * @param lon1 the longitude of the first point
+   * @param lat2 the latitude of the other point
+   * @param lon2 the longitude of the other point
+   * @return
+   */
   public static double distance(final double lat1, final double lon1, final double lat2,
       final double lon2) {
     if (lon1 == lon2 && lat1 == lat2) {
@@ -103,24 +141,39 @@ public class LatLong {
     return dist;
   }
 
+  /**
+   * Computes the distance in meters between two LatLong objects.
+   * @param latLong1 the first LatLong
+   * @param latLong2 the other LatLong
+   * @return the distance in meters
+   */
   public static double distance(final LatLong latLong1, final LatLong latLong2) {
     return distance(latLong1.latitude, latLong1.longitude, latLong2.latitude, latLong2.longitude);
   }
 
+  /**
+   * Computes the distance in meters between this LatLong and an other one.
+   * @param latLong2 the other LatLong
+   * @return the distance in meters
+   */
   public double distance(final LatLong latLong2) {
     return distance(latitude, longitude, latLong2.latitude, latLong2.longitude);
   }
 
-  /* ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */
-  /* :: This function converts decimal degrees to radians : */
-  /* ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */
+  /**
+   * This function converts decimal degrees to radians.
+   * @param deg the desimal degrees
+   * @return the corresponding radians
+   */
   private static double deg2rad(final double deg) {
     return (deg * Math.PI / 180.0);
   }
 
-  /* ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */
-  /* :: This function converts radians to decimal degrees : */
-  /* ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */
+  /**
+   * This function converts radians to decimal degrees.
+   * @param rad the radians
+   * @return the corresponding decimal degrees
+   */
   private static double rad2deg(final double rad) {
     return (rad * 180 / Math.PI);
   }
diff --git a/simpleexample2/core/src/main/java/simpleex/core/LatLongs.java b/simpleexample2/core/src/main/java/simpleex/core/LatLongs.java
index a5e6fa1f80842ef38730d0402f43bb1398064223..a6b992a2b5f488e575e31349891ccc1bd5efc5da 100644
--- a/simpleexample2/core/src/main/java/simpleex/core/LatLongs.java
+++ b/simpleexample2/core/src/main/java/simpleex/core/LatLongs.java
@@ -5,20 +5,40 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
+/**
+ * Represents a sequence of LatLong objects.
+ * @author hal
+ *
+ */
 public class LatLongs implements Iterable<LatLong> {
 
-  final List<LatLong> latLongs = new ArrayList<>();
+  private final List<LatLong> latLongs = new ArrayList<>();
 
+  /**
+   * Initializes an empty LatLongs object.
+   */
   public LatLongs() {}
 
+  /**
+   * Initializes a LatLongs object with the provided latitude, longitude pairs.
+   * @param latLongsArray the latitude, longitude pairs
+   */
   public LatLongs(final double... latLongsArray) {
     addLatLongs(latLongsArray);
   }
 
+  /**
+   * Initializes a LatLongs object with the provided LatLong objects.
+   * @param latLongs the LatLong objects
+   */
   public LatLongs(final LatLong... latLongs) {
     addLatLongs(latLongs);
   }
 
+  /**
+   * Initializes a LatLongs object with the provided LatLong objects.
+   * @param latLongs the LatLong objects
+   */
   public LatLongs(final Collection<LatLong> latLongs) {
     addLatLongs(latLongs);
   }
@@ -28,34 +48,68 @@ public class LatLongs implements Iterable<LatLong> {
     return latLongs.iterator();
   }
 
+  /**
+   * Gets the number of LatLong objects.
+   * @return the number of LatLong objects
+   */
   public int getLatLongCount() {
     return latLongs.size();
   }
 
+  /**
+   * Gets the LatLong object at the provided position.
+   * @param num the position of the LatLong object
+   * @return the LatLong object at the provided position
+   */
   public LatLong getLatLong(final int num) {
     return latLongs.get(num);
   }
 
+  /**
+   * Sets the LatLong object at the provided position.
+   * @param num the position to set
+   * @param latLong the LatLong object to set at the provided position
+   */
   public void setLatLong(final int num, final LatLong latLong) {
     latLongs.set(num, latLong);
   }
 
+  /**
+   * Adds a LatLong object to the end of this LatLongs object.
+   * @param latLong the LatLong object to append
+   * @return the position of the newly added LatLong object
+   */
   public int addLatLong(final LatLong latLong) {
     final int pos = latLongs.size();
     latLongs.add(latLong);
     return pos;
   }
 
+  /**
+   * Adds a collection of LatLong object to the end of this LatLongs object.
+   * @param latLongs the collection of LatLong objects to append
+   * @return the position where the LatLong objects were added
+   */
   public final int addLatLongs(final Collection<LatLong> latLongs) {
     final int pos = this.latLongs.size();
     this.latLongs.addAll(latLongs);
     return pos;
   }
 
+  /**
+   * Adds a the provided LatLong objects to the end of this LatLongs object.
+   * @param latLongs the LatLong objects to add
+   * @return the position where the LatLong objects were added
+   */
   public final int addLatLongs(final LatLong... latLongs) {
     return addLatLongs(List.of(latLongs));
   }
 
+  /**
+   * Adds a the provided latitude, longitude pairs to the end of this LatLongs object.
+   * @param latLongsArray the latitude, longitude pairs
+   * @return the position where the LatLong objects were added
+   */
   public final int addLatLongs(final double... latLongsArray) {
     final Collection<LatLong> latLongs = new ArrayList<>(latLongsArray.length / 2);
     for (int i = 0; i < latLongsArray.length; i += 2) {
@@ -64,6 +118,11 @@ public class LatLongs implements Iterable<LatLong> {
     return addLatLongs(latLongs);
   }
 
+  /**
+   * Removes the LatLong object at the provided position.
+   * @param num the position to remove
+   * @return the removed LatLong object
+   */
   public LatLong removeLatLong(final int num) {
     return latLongs.remove(num);
   }
diff --git a/simpleexample2/core/src/main/java/simpleex/json/LatLongDeserializer.java b/simpleexample2/core/src/main/java/simpleex/json/LatLongDeserializer.java
index ddf7f3ba2534dc2a8f7c348df7eee2930036e56b..37636474cb2238d23ce69fac1df0274ee569d3d3 100644
--- a/simpleexample2/core/src/main/java/simpleex/json/LatLongDeserializer.java
+++ b/simpleexample2/core/src/main/java/simpleex/json/LatLongDeserializer.java
@@ -10,6 +10,11 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.io.IOException;
 import simpleex.core.LatLong;
 
+/**
+ * JSON serializer for LatLong.
+ * @author hal
+ *
+ */
 public class LatLongDeserializer extends JsonDeserializer<LatLong> {
 
   private static final int ARRAY_JSON_NODE_SIZE = 2;
@@ -21,7 +26,12 @@ public class LatLongDeserializer extends JsonDeserializer<LatLong> {
     return deserialize(jsonNode);
   }
 
-  public LatLong deserialize(final JsonNode jsonNode) throws JsonProcessingException {
+  /**
+   * Decodes the provided JsonNode to a LatLong object.
+   * @param jsonNode the JsonNode to decode
+   * @return the corresponding LatLong object
+   */
+  public LatLong deserialize(final JsonNode jsonNode) {
     if (jsonNode instanceof ObjectNode) {
       final ObjectNode objectNode = (ObjectNode) jsonNode;
       final double latitude = objectNode.get(LatLongSerializer.LATITUDE_FIELD_NAME).asDouble();
diff --git a/simpleexample2/core/src/main/java/simpleex/json/LatLongsModule.java b/simpleexample2/core/src/main/java/simpleex/json/LatLongsModule.java
index 5359613e1c889d9ab4750aed813371ba0bbda054..95fbd02a6e86e083fbc0304618225411d73c39e0 100644
--- a/simpleexample2/core/src/main/java/simpleex/json/LatLongsModule.java
+++ b/simpleexample2/core/src/main/java/simpleex/json/LatLongsModule.java
@@ -7,6 +7,11 @@ import com.fasterxml.jackson.databind.module.SimpleSerializers;
 import simpleex.core.LatLong;
 import simpleex.core.LatLongs;
 
+/**
+ * A Module for LatLongs serialization/deserialization.
+ * @author hal
+ *
+ */
 public class LatLongsModule extends Module {
 
   @Override
@@ -22,6 +27,9 @@ public class LatLongsModule extends Module {
   private final SimpleSerializers serializers = new SimpleSerializers();
   private final SimpleDeserializers deserializers = new SimpleDeserializers();
 
+  /**
+   * Initializes the LatLongsModule with appropriate serializers.
+   */
   public LatLongsModule() {
     serializers.addSerializer(LatLong.class, new LatLongSerializer());
     serializers.addSerializer(LatLongs.class, new LatLongsSerializer());
diff --git a/simpleexample2/core/src/test/java/core/LibraryTest.java b/simpleexample2/core/src/test/java/core/LibraryTest.java
deleted file mode 100644
index 4b2d800c5c332304381795fc4075a39b386af0ad..0000000000000000000000000000000000000000
--- a/simpleexample2/core/src/test/java/core/LibraryTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * This Java source file was generated by the Gradle 'init' task.
- */
-package core;
-
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-public class LibraryTest {
-    @Test public void testSomeLibraryMethod() {
-        Library classUnderTest = new Library();
-        assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod());
-    }
-}
diff --git a/simpleexample2/core/src/test/java/simpleex/core/LatLongsTest.java b/simpleexample2/core/src/test/java/simpleex/core/LatLongsTest.java
index dee7f31471ce0842eeb73c18ecff5c0c17be779f..f493e45f188efa81479fd043d063af4ced89b893 100644
--- a/simpleexample2/core/src/test/java/simpleex/core/LatLongsTest.java
+++ b/simpleexample2/core/src/test/java/simpleex/core/LatLongsTest.java
@@ -10,6 +10,9 @@ public class LatLongsTest {
 
   private LatLongs latLongs;
 
+  /**
+   * Setup method, running before each test method.
+   */
   @Before
   public void setUp() {
     latLongs = new LatLongs();
diff --git a/simpleexample2/core/src/test/java/simpleex/json/LatLongsJsonTest.java b/simpleexample2/core/src/test/java/simpleex/json/LatLongsJsonTest.java
index c233c8d4b19494927df665aec4715c036b1352ea..079cab29ef6164db476c972c9d3d59ec70de72df 100644
--- a/simpleexample2/core/src/test/java/simpleex/json/LatLongsJsonTest.java
+++ b/simpleexample2/core/src/test/java/simpleex/json/LatLongsJsonTest.java
@@ -9,6 +9,7 @@ import simpleex.core.LatLongs;
 public class LatLongsJsonTest {
 
   private final ObjectMapper objectMapper = new ObjectMapper();
+
   {
     objectMapper.registerModule(new LatLongsModule());
   }
@@ -18,10 +19,19 @@ public class LatLongsJsonTest {
     Assert.assertEquals(expected, actual.replaceAll("\\s+", ""));
   }
 
+  private LatLong latLong1() {
+    return new LatLong(63.1, 12.3);
+  }
+
+  private LatLong latLong2() {
+    return new LatLong(63.0, 12.4);
+  }
+
   @Test
   public void testLatLongsSerialization() throws Exception {
-    final String actualJson = objectMapper.writeValueAsString(new LatLongs(new LatLong(63.1, 12.3), new LatLong(63.0, 12.4)));
-    final String expectedJson = "[{\"latitude\":63.1,\"longitude\":12.3},{\"latitude\":63.0,\"longitude\":12.4}]";
+    final String actualJson = objectMapper.writeValueAsString(new LatLongs(latLong1(), latLong2()));
+    final String expectedJson = "[{\"latitude\":63.1,\"longitude\":12.3},"
+        + "{\"latitude\":63.0,\"longitude\":12.4}]";
     assertEqualsIgnoreWhitespace(expectedJson, actualJson);
   }
 
@@ -30,7 +40,7 @@ public class LatLongsJsonTest {
     final String json = "[{\"latitude\":63.1,\"longitude\":12.3}, [63.0,12.4]]";
     final LatLongs latLongs = objectMapper.readValue(json, LatLongs.class);
     Assert.assertEquals(2, latLongs.getLatLongCount());
-    Assert.assertEquals(new LatLong(63.1, 12.3), latLongs.getLatLong(0));
-    Assert.assertEquals(new LatLong(63.0, 12.4), latLongs.getLatLong(1));
+    Assert.assertEquals(latLong1(), latLongs.getLatLong(0));
+    Assert.assertEquals(latLong2(), latLongs.getLatLong(1));
   }
 }
diff --git a/simpleexample2/fxui/README.md b/simpleexample2/fxui/README.md
index 9237c57f38ad7a60fdc394b628b5d5a148e86624..9839af859170433729c3229d48c87758c457b9e9 100644
--- a/simpleexample2/fxui/README.md
+++ b/simpleexample2/fxui/README.md
@@ -2,15 +2,6 @@
 
 Dette prosjektet inneholder brukergrensesnittlaget for [simpleexample2](../README.md).
 
-## Organisering av koden
-
-Prosjektet er organisert med 2 * 2 = 4 kildekodemapper, kode og ressurser for henholdsvis applikasjonen selv og testene:
-
-- **src/main/java** for koden til applikasjonen
-- **src/main/resources** for tilhørende ressurser, f.eks. FXML-filer, som brukes av applikasjonen.
-- **src/test/java** for testkoden
-- **src/test/resources** for tilhørende ressurser, f.eks. FXML-filer, som brukes av testene.
-
 ## Brukergrensesnittlaget
 
 Brukergrensesnittlaget inneholder alle klasser og logikk knyttet til visning og handlinger på dataene i domenelaget. Brukergrensesnittet til vår app viser frem en liste av geo-lokasjoner, den som velges vises på et kart. En flytte og legge til geo-lokasjoner. Samlingen med geo-lokasjoner kan lagres og evt. leses inn igjen.
diff --git a/simpleexample2/fxui/src/main/java/fxui/Library.java b/simpleexample2/fxui/src/main/java/fxui/Library.java
deleted file mode 100644
index 8c9ecf64eac81dadd5a8046fa5aec4c8f4196e84..0000000000000000000000000000000000000000
--- a/simpleexample2/fxui/src/main/java/fxui/Library.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * This Java source file was generated by the Gradle 'init' task.
- */
-package fxui;
-
-public class Library {
-    public boolean someLibraryMethod() {
-        return true;
-    }
-}
diff --git a/simpleexample2/fxui/src/main/java/simpleex/ui/DraggableNodeController.java b/simpleexample2/fxui/src/main/java/simpleex/ui/DraggableNodeController.java
index e3325203ee6663ea025d2be677f24a93cda970ea..e1f85bbcb736148330f5839e4143f2f5e5dde776 100644
--- a/simpleexample2/fxui/src/main/java/simpleex/ui/DraggableNodeController.java
+++ b/simpleexample2/fxui/src/main/java/simpleex/ui/DraggableNodeController.java
@@ -5,20 +5,37 @@ import javafx.geometry.Point2D;
 import javafx.scene.Node;
 import javafx.scene.input.MouseEvent;
 
+/**
+ * Helper controller for handling dragging a map or marker.
+ * @author hal
+ *
+ */
 public class DraggableNodeController {
 
   private final NodeDraggedHandler nodeDraggedHandler;
 
+  /**
+   * Initializes with no NodeDraggedHandler.
+   */
   public DraggableNodeController() {
     this(null);
   }
 
+  /**
+   * Initializes with a specific NodeDraggedHandler.
+   * @param nodeDraggedHandler the NodeDraggedHandler
+   */
   public DraggableNodeController(final NodeDraggedHandler nodeDraggedHandler) {
-    this.nodeDraggedHandler = (nodeDraggedHandler != null ? nodeDraggedHandler : (node, x, y) -> {});
+    final NodeDraggedHandler noOp = (node, x, y) -> {};
+    this.nodeDraggedHandler = (nodeDraggedHandler != null ? nodeDraggedHandler : noOp);
   }
 
   private boolean immediate = false;
 
+  /**
+   * Sets whether feedback is immediate or not.
+   * @param immediate the new immediate value
+   */
   public void setImmediate(final boolean immediate) {
     this.immediate = immediate;
   }
@@ -31,12 +48,20 @@ public class DraggableNodeController {
   private final EventHandler<MouseEvent> mouseDraggedHandler = this::mouseDragged;
   private final EventHandler<MouseEvent> mouseReleasedHandler = this::mouseReleased;
 
+  /**
+   * Attaches this controller to the provided Node (e.g. map or marker).
+   * @param node the Node to attach the controller to
+   */
   public void attach(final Node node) {
     node.setOnMousePressed(mousePressedHandler);
     node.setOnMouseDragged(mouseDraggedHandler);
     node.setOnMouseReleased(mouseReleasedHandler);
   }
 
+  /**
+   * Detaches this controller from the provided Node (e.g. map or marker).
+   * @param node the Node to detach the controller from
+   */
   public void detach(final Node node) {
     node.setOnMousePressed(null);
     node.setOnMouseDragged(null);
@@ -84,7 +109,18 @@ public class DraggableNodeController {
     }
   }
 
+  /**
+   * Interface for node drag feedback.
+   * @author hal
+   *
+   */
   public interface NodeDraggedHandler {
-    public void nodeDragged(Node currentNode2, double dx, double dy);
+    /**
+     * Callback for providing feedback during drag.
+     * @param node the dragged node
+     * @param dx the relative x movement
+     * @param dy the relative y movement
+     */
+    public void nodeDragged(Node node, double dx, double dy);
   }
 }
diff --git a/simpleexample2/fxui/src/main/java/simpleex/ui/FxApp.java b/simpleexample2/fxui/src/main/java/simpleex/ui/FxApp.java
index a776467a8353cc25cc98d0b3a55aa22934c70e72..cd1bdc3328b893269b2a1eb683f226a5019fccd4 100644
--- a/simpleexample2/fxui/src/main/java/simpleex/ui/FxApp.java
+++ b/simpleexample2/fxui/src/main/java/simpleex/ui/FxApp.java
@@ -20,6 +20,10 @@ public class FxApp extends Application {
     stage.show();
   }
 
+  /**
+   * Launches the app.
+   * @param args the command line arguments
+   */
   public static void main(final String[] args) {
     // only needed on ios
     System.setProperty("os.target", "ios");
diff --git a/simpleexample2/fxui/src/main/java/simpleex/ui/FxAppController.java b/simpleexample2/fxui/src/main/java/simpleex/ui/FxAppController.java
index c0044403e211629f96e00db954afcaad010dce8e..03ce1bba8d8193f1b66b2ee30bd8abccd23d25d9 100644
--- a/simpleexample2/fxui/src/main/java/simpleex/ui/FxAppController.java
+++ b/simpleexample2/fxui/src/main/java/simpleex/ui/FxAppController.java
@@ -44,27 +44,39 @@ FxAppController --> ListView: "locationListView"
 @enduml
  */
 
+/**
+ * The controller for the app.
+ * @author hal
+ *
+ */
 public class FxAppController {
 
   private LatLongs latLongs;
 
+  /**
+   * Initializes the controller.
+   */
   public FxAppController() {
     latLongs = new LatLongs();
   }
 
+  /**
+   * Gets the LatLongs objects used by the controller.
+   * @return the controller's LatLongs objects
+   */
   public LatLongs getLatLongs() {
     return latLongs;
   }
 
-  // to make it testable
+  /**
+   * Sets the LatLongs objects used by the controller.
+   * @param latLongs the LatLongs object to use
+   */
   public void setLatLongs(final LatLongs latLongs) {
     this.latLongs = latLongs;
     updateLocationViewList(0);
   }
 
-  // @FXML
-  // private FileMenuController fileMenuController;
-
   @FXML
   private ListView<LatLong> locationListView;
 
@@ -84,7 +96,7 @@ public class FxAppController {
     // map stuff
     // mapView.getChildren().add(MapTileLayer.getOpenStreetMapLayer());
     zoomSlider.valueProperty()
-    .addListener((prop, oldValue, newValue) -> mapView.setZoomLevel(zoomSlider.getValue()));
+      .addListener((prop, oldValue, newValue) -> mapView.setZoomLevel(zoomSlider.getValue()));
     zoomSlider.setValue(8);
     markersParent = new MapItemsControl<MapNode>();
     mapView.getChildren().add(markersParent);
@@ -192,7 +204,7 @@ public class FxAppController {
     final FileChooser fileChooser = getFileChooser();
     final File selection = fileChooser.showOpenDialog(null);
     if (selection != null) {
-      try (InputStream input = new FileInputStream(selection) ){
+      try (InputStream input = new FileInputStream(selection)) {
         setLatLongs(getObjectMapper().readValue(input, LatLongs.class));
       } catch (final IOException e) {
         showExceptionDialog("Oops, problem when opening " + selection, e);
@@ -202,6 +214,10 @@ public class FxAppController {
 
   private ObjectMapper objectMapper;
 
+  /**
+   * Gets the ObjectMapper used by this controller.
+   * @return the ObjectMapper used by this controller
+   */
   public ObjectMapper getObjectMapper() {
     if (objectMapper == null) {
       objectMapper = new ObjectMapper();
@@ -227,7 +243,7 @@ public class FxAppController {
   void handleSaveAction() {
     final FileChooser fileChooser = getFileChooser();
     final File selection = fileChooser.showSaveDialog(null);
-    if (selection != null ) {
+    if (selection != null) {
       try (OutputStream outputStream = new FileOutputStream(selection, false)) {
         getObjectMapper().writeValue(outputStream, getLatLongs());
       } catch (final IOException e) {
diff --git a/simpleexample2/fxui/src/main/java/simpleex/ui/MapMarker.java b/simpleexample2/fxui/src/main/java/simpleex/ui/MapMarker.java
index 47ece587946e59d25e8cbe4e1d8941b849da1794..56254c69fe0035ecdd4881e5fbb97af5150050df 100644
--- a/simpleexample2/fxui/src/main/java/simpleex/ui/MapMarker.java
+++ b/simpleexample2/fxui/src/main/java/simpleex/ui/MapMarker.java
@@ -6,8 +6,17 @@ import javafx.scene.paint.Color;
 import javafx.scene.shape.Circle;
 import simpleex.core.LatLong;
 
+/**
+ * A circle map marker.
+ * @author hal
+ *
+ */
 public class MapMarker extends MapItem<LatLong> {
 
+  /**
+   * Initializes the MapMarker with the provided location.
+   * @param latLong the location
+   */
   public MapMarker(final LatLong latLong) {
     setLocation(latLong);
     final Circle circle = new Circle();
@@ -16,6 +25,10 @@ public class MapMarker extends MapItem<LatLong> {
     getChildren().add(circle);
   }
 
+  /**
+   * Sets the location of this MapMarker.
+   * @param latLong the new location
+   */
   public final void setLocation(final LatLong latLong) {
     setLocation(new Location(latLong.getLatitude(), latLong.getLongitude()));
   }
diff --git a/simpleexample2/fxui/src/test/java/fxui/LibraryTest.java b/simpleexample2/fxui/src/test/java/fxui/LibraryTest.java
deleted file mode 100644
index 4649b26b84f2e297d0176d07609221a619501418..0000000000000000000000000000000000000000
--- a/simpleexample2/fxui/src/test/java/fxui/LibraryTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * This Java source file was generated by the Gradle 'init' task.
- */
-package fxui;
-
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-public class LibraryTest {
-    @Test public void testSomeLibraryMethod() {
-        Library classUnderTest = new Library();
-        assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod());
-    }
-}
diff --git a/simpleexample2/fxui/src/test/java/simpleex/ui/FxAppTest.java b/simpleexample2/fxui/src/test/java/simpleex/ui/FxAppTest.java
index 0b3f7d1793f8f2181bbffaa5b2393f687d8eb5c3..db2878a0fd38c3dfb4a56812afb879a7b97e70ea 100644
--- a/simpleexample2/fxui/src/test/java/simpleex/ui/FxAppTest.java
+++ b/simpleexample2/fxui/src/test/java/simpleex/ui/FxAppTest.java
@@ -22,6 +22,9 @@ import simpleex.core.LatLongs;
 
 public class FxAppTest extends ApplicationTest {
 
+  /**
+   * Setup method for headless tests using monocle.
+   */
   @BeforeClass
   public static void headless() {
     if (Boolean.valueOf(System.getProperty("gitlab-ci", "false"))) {
@@ -60,7 +63,7 @@ public class FxAppTest extends ApplicationTest {
     latLongs = mock(LatLongs.class);
     // get nth LatLong object
     when(latLongs.getLatLong(anyInt()))
-    .then(invocation -> latLongList.get(invocation.getArgument(0)));
+      .then(invocation -> latLongList.get(invocation.getArgument(0)));
     // get the number of LatLong objects
     when(latLongs.getLatLongCount()).then(invocation -> latLongList.size());
     // iterator for LatLong objects
diff --git a/simpleexample2/restapi/.gitignore b/simpleexample2/restapi/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1b6985c0094c8e3db5f1c6e2c4d66b82f325284f
--- /dev/null
+++ b/simpleexample2/restapi/.gitignore
@@ -0,0 +1,5 @@
+# Ignore Gradle project-specific cache directory
+.gradle
+
+# Ignore Gradle build output directory
+build
diff --git a/simpleexample2/restapi/README.md b/simpleexample2/restapi/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..71af46e178cacd62831dc56cce7aee82acebb807
--- /dev/null
+++ b/simpleexample2/restapi/README.md
@@ -0,0 +1,7 @@
+# Modul for REST-api
+
+Dette prosjektet inneholder REST-api for [simpleexample2](../README.md).
+
+## REST-api-et
+
+## Bygging med gradle
diff --git a/simpleexample2/restapi/build.gradle b/simpleexample2/restapi/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..30d50424d187f4799287a0a5ed91b147ef59a42b
--- /dev/null
+++ b/simpleexample2/restapi/build.gradle
@@ -0,0 +1,14 @@
+plugins {
+	id 'java-library'
+}
+
+dependencies {
+	implementation project(':core')
+
+    compile "com.fasterxml.jackson.core:jackson-core:${depVersions.jackson}"
+    compile "com.fasterxml.jackson.core:jackson-databind:${depVersions.jackson}"
+    compile "com.fasterxml.jackson.core:jackson-annotations:${depVersions.jackson}"
+
+    compile "javax.ws.rs:javax.ws.rs-api:2.1.1"
+    compile "javax.inject:javax.inject:1"
+}
diff --git a/simpleexample2/restapi/gradle/wrapper/gradle-wrapper.jar b/simpleexample2/restapi/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..5c2d1cf016b3885f6930543d57b744ea8c220a1a
Binary files /dev/null and b/simpleexample2/restapi/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/simpleexample2/restapi/gradle/wrapper/gradle-wrapper.properties b/simpleexample2/restapi/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f4d7b2bf616f7674854ff527df47b371b72472da
--- /dev/null
+++ b/simpleexample2/restapi/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/simpleexample2/restapi/gradlew b/simpleexample2/restapi/gradlew
new file mode 100755
index 0000000000000000000000000000000000000000..b0d6d0ab5deb588123dd658f0b079934ee05a72e
--- /dev/null
+++ b/simpleexample2/restapi/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/simpleexample2/restapi/gradlew.bat b/simpleexample2/restapi/gradlew.bat
new file mode 100644
index 0000000000000000000000000000000000000000..15e1ee37a70d7dfdfd8cf727022e117b6f6153a7
--- /dev/null
+++ b/simpleexample2/restapi/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/simpleexample2/restapi/settings.gradle b/simpleexample2/restapi/settings.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..162600e96ecdfe016370e801c84b4876862fa573
--- /dev/null
+++ b/simpleexample2/restapi/settings.gradle
@@ -0,0 +1,10 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * The settings file is used to specify which projects to include in your build.
+ *
+ * Detailed information about configuring a multi-project build in Gradle can be found
+ * in the user manual at https://docs.gradle.org/5.4.1/userguide/multi_project_builds.html
+ */
+
+rootProject.name = 'restapi'
diff --git a/simpleexample2/restapi/src/main/java/simpleex/restapi/LatLongObjectMapperProvider.java b/simpleexample2/restapi/src/main/java/simpleex/restapi/LatLongObjectMapperProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..df95ad9397077b585211d75e1823b62644b59293
--- /dev/null
+++ b/simpleexample2/restapi/src/main/java/simpleex/restapi/LatLongObjectMapperProvider.java
@@ -0,0 +1,26 @@
+package simpleex.restapi;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.ContextResolver;
+import javax.ws.rs.ext.Provider;
+import simpleex.json.LatLongsModule;
+
+@Provider
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class LatLongObjectMapperProvider implements ContextResolver<ObjectMapper> {
+
+  private final ObjectMapper objectMapper;
+
+  public LatLongObjectMapperProvider() {
+    objectMapper = new ObjectMapper().registerModule(new LatLongsModule());
+  }
+
+  @Override
+  public ObjectMapper getContext(final Class<?> type) {
+    return objectMapper;
+  }
+}
diff --git a/simpleexample2/restapi/src/main/java/simpleex/restapi/LatLongService.java b/simpleexample2/restapi/src/main/java/simpleex/restapi/LatLongService.java
new file mode 100644
index 0000000000000000000000000000000000000000..b76fefa5c9242676b304b09cb1937f13ac83e7f4
--- /dev/null
+++ b/simpleexample2/restapi/src/main/java/simpleex/restapi/LatLongService.java
@@ -0,0 +1,76 @@
+package simpleex.restapi;
+
+import java.util.List;
+import javax.inject.Inject;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import simpleex.core.LatLong;
+import simpleex.core.LatLongs;
+
+@Path(LatLongService.LAT_LONG_SERVICE_PATH)
+public class LatLongService {
+
+  public static final String LAT_LONG_SERVICE_PATH = "latLong";
+
+  @Inject
+  private LatLongs latLongs;
+
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public LatLongs getLatLongs() {
+    return latLongs;
+  }
+
+  @GET
+  @Path("/{num}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public LatLong getLatLong(@PathParam("num") int num) {
+    if (num < 0) {
+      num = latLongs.getLatLongCount() + num;
+    }
+    return latLongs.getLatLong(num);
+  }
+
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public int addLatLongs(final List<LatLong> latLongs) {
+    int result = -1;
+    for (final LatLong latLong : latLongs) {
+      final int pos = this.latLongs.addLatLong(latLong);
+      if (result < 0) {
+        result = pos;
+      }
+    }
+    return result;
+  }
+
+  @PUT
+  @Path("/{num}")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public int setLatLong(final LatLong latLong, @PathParam("num") int num) {
+    if (num < 0) {
+      num = latLongs.getLatLongCount() + num;
+    }
+    latLongs.setLatLong(num, latLong);
+    return num;
+  }
+
+  @DELETE
+  @Path("/{num}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public LatLong deleteLatLong(@PathParam("num") int num) {
+    if (num < 0) {
+      num = latLongs.getLatLongCount() + num;
+    }
+    return latLongs.removeLatLong(num);
+  }
+}
diff --git a/simpleexample2/restserver/.gitignore b/simpleexample2/restserver/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1b6985c0094c8e3db5f1c6e2c4d66b82f325284f
--- /dev/null
+++ b/simpleexample2/restserver/.gitignore
@@ -0,0 +1,5 @@
+# Ignore Gradle project-specific cache directory
+.gradle
+
+# Ignore Gradle build output directory
+build
diff --git a/simpleexample2/restserver/README.md b/simpleexample2/restserver/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0edd3dc817cc518fbda480a0aee57b603f108b65
--- /dev/null
+++ b/simpleexample2/restserver/README.md
@@ -0,0 +1,7 @@
+# Modul for web-serveren
+
+Dette prosjektet inneholder web-serveren med REST-api-et for [simpleexample2](../README.md).
+
+## Web-serveren
+
+## Bygging med gradle
diff --git a/simpleexample2/restserver/build.gradle b/simpleexample2/restserver/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..1ca5bba49cb80e54aa9e7b52f0571bc1bcac4029
--- /dev/null
+++ b/simpleexample2/restserver/build.gradle
@@ -0,0 +1,40 @@
+plugins {
+	id 'application'
+}
+
+ext {
+    slf4jVersion = '1.7.25'
+    jerseyVersion = '2.28'
+}
+
+mainClassName = 'multiex.jersey.LatLongGrizzlyApp'
+
+dependencies {
+	implementation project(':core')
+	implementation project(':restapi')
+
+    compile "org.slf4j:slf4j-api:$slf4jVersion"
+    compile "org.slf4j:slf4j-simple:$slf4jVersion"
+
+    compile "org.glassfish.jersey.core:jersey-server:$jerseyVersion"
+    compile "org.glassfish.jersey.media:jersey-media-json-jackson:$jerseyVersion"
+    compile "org.glassfish.jersey.inject:jersey-hk2:$jerseyVersion"
+
+	testImplementation 'junit:junit:4.12'
+    testImplementation "org.glassfish.jersey.test-framework:jersey-test-framework-util:$jerseyVersion"
+
+	// See https://jersey.github.io/documentation/latest/deployment.html#deployment.http for various server options
+    compile "org.glassfish.jersey.containers:jersey-container-grizzly2-http:$jerseyVersion"
+	testImplementation "org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:$jerseyVersion"
+
+	testRuntime 'javax.activation:activation:1.1.1'
+    testRuntime 'javax.xml.bind:jaxb-api:2.3.0'
+    testRuntime 'com.sun.xml.bind:jaxb-core:2.3.0'
+    testRuntime 'com.sun.xml.bind:jaxb-impl:2.3.0'
+}
+
+test {
+    testLogging {
+   		showStandardStreams = true
+    }
+}
diff --git a/simpleexample2/restserver/gradle/wrapper/gradle-wrapper.jar b/simpleexample2/restserver/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..5c2d1cf016b3885f6930543d57b744ea8c220a1a
Binary files /dev/null and b/simpleexample2/restserver/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/simpleexample2/restserver/gradle/wrapper/gradle-wrapper.properties b/simpleexample2/restserver/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f4d7b2bf616f7674854ff527df47b371b72472da
--- /dev/null
+++ b/simpleexample2/restserver/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/simpleexample2/restserver/gradlew b/simpleexample2/restserver/gradlew
new file mode 100755
index 0000000000000000000000000000000000000000..b0d6d0ab5deb588123dd658f0b079934ee05a72e
--- /dev/null
+++ b/simpleexample2/restserver/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/simpleexample2/restserver/gradlew.bat b/simpleexample2/restserver/gradlew.bat
new file mode 100644
index 0000000000000000000000000000000000000000..15e1ee37a70d7dfdfd8cf727022e117b6f6153a7
--- /dev/null
+++ b/simpleexample2/restserver/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/simpleexample2/restserver/settings.gradle b/simpleexample2/restserver/settings.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..21646316fa228af3f9bd38ef2aaefc691a9b512f
--- /dev/null
+++ b/simpleexample2/restserver/settings.gradle
@@ -0,0 +1,10 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * The settings file is used to specify which projects to include in your build.
+ *
+ * Detailed information about configuring a multi-project build in Gradle can be found
+ * in the user manual at https://docs.gradle.org/5.4.1/userguide/multi_project_builds.html
+ */
+
+rootProject.name = 'restserver'
diff --git a/simpleexample2/restserver/src/main/java/simpleex/restserver/LatLongConfig.java b/simpleexample2/restserver/src/main/java/simpleex/restserver/LatLongConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb37c133bb043195b3ae88d086ff62990baf151e
--- /dev/null
+++ b/simpleexample2/restserver/src/main/java/simpleex/restserver/LatLongConfig.java
@@ -0,0 +1,31 @@
+package simpleex.restserver;
+
+import org.glassfish.hk2.utilities.binding.AbstractBinder;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import simpleex.core.LatLongs;
+import simpleex.restapi.LatLongObjectMapperProvider;
+import simpleex.restapi.LatLongService;
+
+public class LatLongConfig extends ResourceConfig {
+
+  final LatLongs latLongs;
+
+  public LatLongConfig() {
+    this(new LatLongs());
+  }
+
+  public LatLongConfig(final LatLongs latLongs) {
+    this.latLongs = latLongs;
+    register(LatLongService.class);
+    register(LatLongObjectMapperProvider.class);
+    register(JacksonFeature.class);
+
+    register(new AbstractBinder() {
+      @Override
+      protected void configure() {
+        bind(latLongs);
+      }
+    });
+  }
+}
diff --git a/simpleexample2/restserver/src/main/java/simpleex/restserver/LatLongGrizzlyApp.java b/simpleexample2/restserver/src/main/java/simpleex/restserver/LatLongGrizzlyApp.java
new file mode 100644
index 0000000000000000000000000000000000000000..6e7fae7d74fb178589a878d5ed6777ce4f0549db
--- /dev/null
+++ b/simpleexample2/restserver/src/main/java/simpleex/restserver/LatLongGrizzlyApp.java
@@ -0,0 +1,30 @@
+package simpleex.restserver;
+
+import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+
+public class LatLongGrizzlyApp {
+
+	private static final URI BASE_URI = URI.create("http://localhost:8080/");
+
+	public static void main(final String[] args) {
+		try {
+			final ResourceConfig resourceConfig = new LatLongConfig();
+			final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(BASE_URI, resourceConfig);
+			Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+				@Override
+				public void run() {
+					server.shutdownNow();
+				}
+			}));
+			Thread.currentThread().join();
+		} catch (final InterruptedException ex) {
+			Logger.getLogger(LatLongGrizzlyApp.class.getName()).log(Level.SEVERE, null, ex);
+		}
+	}
+}
diff --git a/simpleexample2/restserver/src/test/java/simpleex/restserver/LatLongsServiceTest.java b/simpleexample2/restserver/src/test/java/simpleex/restserver/LatLongsServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..56b000452e829ede2bc108be1adbb5905b5d3546
--- /dev/null
+++ b/simpleexample2/restserver/src/test/java/simpleex/restserver/LatLongsServiceTest.java
@@ -0,0 +1,97 @@
+package simpleex.restserver;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.util.Collections;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import simpleex.core.LatLong;
+import simpleex.restapi.LatLongObjectMapperProvider;
+import simpleex.restapi.LatLongService;
+
+public class LatLongsServiceTest extends SimpleExJerseyTest {
+
+  private static final String LAT_LONG_SERVICE_PATH = LatLongService.LAT_LONG_SERVICE_PATH;
+
+  private ObjectMapper objectMapper;
+
+  @Override
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+    objectMapper = new LatLongObjectMapperProvider().getContext(getClass());
+  }
+
+  @Test
+  public void testPostGetPutGetDelete() throws Exception {
+    // POST, i.e. add
+    final LatLong latLong = new LatLong(63, 11);
+    final Response postResponse = target(LAT_LONG_SERVICE_PATH)
+        .request("application/json; charset=UTF-8")
+        .post(Entity.entity(objectMapper.writeValueAsString(Collections.singleton(latLong)), MediaType.APPLICATION_JSON));
+    Assert.assertEquals(200, postResponse.getStatus());
+    final Integer postNum = objectMapper.readValue(postResponse.readEntity(String.class), Integer.class);
+    Assert.assertEquals(0, postNum.intValue());
+    // GET
+    testGet(0, latLong);
+    // PUT, i.e. set
+    final LatLong altLatLong = new LatLong(63, 11);
+
+    final Response putResponse = target(LAT_LONG_SERVICE_PATH).path("0")
+        .request("application/json; charset=UTF-8")
+        .put(Entity.entity(objectMapper.writeValueAsString(latLong), MediaType.APPLICATION_JSON));
+    Assert.assertEquals(200, putResponse.getStatus());
+    final Integer putNum = objectMapper.readValue(putResponse.readEntity(String.class), Integer.class);
+    Assert.assertEquals(0, putNum.intValue());
+    // GET
+    testGet(0, altLatLong);
+    // DELETE, i.e. remove
+    final Response deleteResponse = target(LAT_LONG_SERVICE_PATH).path("0")
+        .request("application/json; charset=UTF-8")
+        .delete();
+    testContent(deleteResponse.readEntity(String.class), altLatLong);
+  }
+
+  protected void doJsonOutput(final HttpURLConnection postCon, final Object content)
+      throws IOException, JsonGenerationException, JsonMappingException {
+    postCon.setDoOutput(true);
+    final ByteArrayOutputStream out = new ByteArrayOutputStream();
+    objectMapper.writeValue(out, content);
+    out.close();
+    final byte[] postBytes = out.toByteArray();
+    postCon.setFixedLengthStreamingMode(postBytes.length);
+    postCon.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+    postCon.connect();
+    try (OutputStream conOut = postCon.getOutputStream()) {
+      conOut.write(postBytes);
+    }
+  }
+
+  protected void testGet(final int num, final LatLong latLong)
+      throws MalformedURLException, IOException, ProtocolException, JsonParseException, JsonMappingException {
+    // GET
+    final Response response = target(LAT_LONG_SERVICE_PATH).path(String.valueOf(num))
+        .request("application/json; charset=UTF-8")
+        .get();
+    Assert.assertEquals(200, response.getStatus());
+    testContent(response.readEntity(String.class), latLong);
+  }
+
+  protected void testContent(final String content, final LatLong latLong)
+      throws IOException, JsonParseException, JsonMappingException {
+    final LatLong getLatLong = objectMapper.readValue(content, LatLong.class);
+    Assert.assertEquals(latLong, getLatLong);
+  }
+}
diff --git a/simpleexample2/restserver/src/test/java/simpleex/restserver/SimpleExJerseyTest.java b/simpleexample2/restserver/src/test/java/simpleex/restserver/SimpleExJerseyTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d13c651c1cb163cda5ba0eff9577ee5d6a9da8a8
--- /dev/null
+++ b/simpleexample2/restserver/src/test/java/simpleex/restserver/SimpleExJerseyTest.java
@@ -0,0 +1,32 @@
+package simpleex.restserver;
+
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory;
+import org.glassfish.jersey.test.spi.TestContainerException;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
+
+public abstract class SimpleExJerseyTest extends JerseyTest {
+
+	protected boolean shouldLog() {
+		return false;
+	}
+
+	@Override
+	protected ResourceConfig configure() {
+		final LatLongConfig config = new LatLongConfig();
+		if (shouldLog()) {
+			enable(TestProperties.LOG_TRAFFIC);
+			enable(TestProperties.DUMP_ENTITY);
+			config.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, "WARNING");
+		}
+		return config;
+	}
+
+	@Override
+	protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
+		return new GrizzlyTestContainerFactory();
+	}
+}
diff --git a/simpleexample2/settings.gradle b/simpleexample2/settings.gradle
index 25b02a8acff6333080322490b76aa783fe9f0179..f7a17369b5c8cd3635905786ecedb2c9d3936f66 100644
--- a/simpleexample2/settings.gradle
+++ b/simpleexample2/settings.gradle
@@ -10,3 +10,5 @@
 rootProject.name = 'simpleexample2'
 include 'core'
 include 'fxui'
+include 'restapi'
+include 'restserver'