diff --git a/simpleexample2/core/src/main/java/simpleex/core/LatLong.java b/simpleexample2/core/src/main/java/simpleex/core/LatLong.java
index 36f118497df7fffb33cafd90f8c7308237b9b78e..3c3de07c21a7bbc36856cfaf43580af832feb371 100644
--- a/simpleexample2/core/src/main/java/simpleex/core/LatLong.java
+++ b/simpleexample2/core/src/main/java/simpleex/core/LatLong.java
@@ -15,6 +15,8 @@ public class LatLong {
   private final double latitude;
   private final double longitude;
 
+  private MetaData metaData;
+
   /**
    * Initialize a LatLong with provided latitude and longitude.
    * @param latitude the latitude
@@ -177,4 +179,24 @@ public class LatLong {
   private static double rad2deg(final double rad) {
     return (rad * 180 / Math.PI);
   }
+
+  /**
+   * Checks if this object has meta data
+   * @return true if this LatLong object has meta data, false otherwise
+   */
+  public boolean hasMetaData() {
+    return metaData != null && (! metaData.isEmpty());
+  }
+
+  /**
+   * Gets the meta data of this object. Will create it if missing,
+   * so it will always be safe to chain a call.
+   * @return the meta data of this object
+   */
+  public MetaData getMetaData() {
+    if (metaData == null) {
+      metaData = new MetaData();
+    }
+    return metaData;
+  }
 }
diff --git a/simpleexample2/core/src/main/java/simpleex/core/MetaData.java b/simpleexample2/core/src/main/java/simpleex/core/MetaData.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd8d8d4212c7493ec950b2078d3ea5ab67bdd6de
--- /dev/null
+++ b/simpleexample2/core/src/main/java/simpleex/core/MetaData.java
@@ -0,0 +1,281 @@
+package simpleex.core;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public class MetaData {
+
+  /**
+   * Name property name
+   */
+  public final static String NAME_PROPERTY = "name";
+  /**
+   * Description property name
+   */
+  public final static String DESCRIPTION_PROPERTY = "description";
+
+  private Collection<String> tags;
+  private List<String> properties;
+
+  /**
+   * Tells if there are tags and/or properties in this object.
+   * @return true if there are tags and/or properties in this object, false otherwise
+   */
+  public boolean isEmpty() {
+    return (tags == null || tags.isEmpty()) && (properties == null || properties.isEmpty());
+  }
+
+  /**
+   * Gets the iterator for the tags.
+   * @return an iterator for the tags
+   */
+  public Iterator<String> tags() {
+    return (tags != null ? tags.iterator() : Collections.emptyIterator());
+  }
+
+  /**
+   * Checks if all the provided tags are present.
+   * @param tags the tags to check
+   * @return true if all the provided tags are present, false otherwise
+   */
+  public boolean hasTags(final String... tags) {
+    if (this.tags == null) {
+      return tags.length == 0;
+    }
+    for (final String tag : tags) {
+      if (! this.tags.contains(tag)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Sets the tags to those provided (old ones are removed).
+   * @param tags the new tags
+   */
+  public void setTags(final String... tags) {
+    if (tags.length == 0)  {
+      this.tags = null;
+    } else {
+      if (this.tags != null) {
+        this.tags.clear();
+      } else {
+        this.tags = new ArrayList<>();
+      }
+      // cannot use addAll, since tags may contain duplicates
+      addTags(tags);
+    }
+  }
+
+  /**
+   * Adds the provided tags.
+   * @param tags the tags to add
+   */
+  public void addTags(final String... tags) {
+    if (this.tags == null && tags.length > 0) {
+      this.tags = new ArrayList<>();
+    }
+    // avoid duplicates
+    for (final String tag : tags) {
+      if (! this.tags.contains(tag)) {
+        this.tags.add(tag);
+      }
+    }
+  }
+
+  /**
+   * Removes the provided tags.
+   * @param tags the tags to remove
+   */
+  public void removeTags(final String... tags) {
+    if (this.tags != null) {
+      this.tags.removeAll(Arrays.asList(tags));
+    }
+    if (this.tags.isEmpty()) {
+      this.tags = null;
+    }
+  }
+
+  /**
+   * Gets the iterator for the tags.
+   * @return an iterator for the tags
+   */
+  public Iterator<String> propertyNames() {
+    if (properties == null || properties.isEmpty()) {
+      return Collections.emptyIterator();
+    }
+    return new Iterator<String>() {
+
+      int pos = 0;
+
+      @Override
+      public boolean hasNext() {
+        return properties == null || pos < properties.size();
+      }
+
+      @Override
+      public String next() {
+        final String propertyName = properties.get(pos);
+        pos += 2;
+        return propertyName;
+      }
+
+
+      @Override
+      public void remove() {
+        pos -= 2;
+        removeProperty(properties.get(pos));
+      }
+    };
+  }
+
+  private int indexOfProperty(final String propertyName) {
+    if (properties != null) {
+      for (int i = 0; i < properties.size(); i += 2)  {
+        if (propertyName.equals(properties.get(i))) {
+          return i;
+        }
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Checks if a property with the provided name is present.
+   * @param propertyName the name to check
+   * @return true if the property is present, false otherwise
+   */
+  public boolean hasProperty(final String propertyName) {
+    return indexOfProperty(propertyName) >= 0;
+  }
+
+  /**
+   * Gets the property value for the provided property name.
+   * @param propertyName the property name
+   * @return the value for the provided property name
+   */
+  public String getProperty(final String propertyName) {
+    final int pos = indexOfProperty(propertyName);
+    if (pos >= 0) {
+      return properties.get(pos + 1);
+    }
+    return null;
+  }
+
+  /**
+   * Gets the property value for the provided property name, as an int.
+   * If the property value doesn't exist or isn't a valid integer, def is returned.
+   * @param propertyName the property name
+   * @return the value for the provided property name, as an int, or def it is missing
+   */
+  public int getIntegerProperty(final String propertyName, final int def) {
+    final int pos = indexOfProperty(propertyName);
+    if (pos >= 0) {
+      try {
+        return Integer.valueOf(properties.get(pos + 1));
+      } catch (final NumberFormatException e) {
+      }
+    }
+    return def;
+  }
+
+  /**
+   * Gets the property value for the provided property name, as a double.
+   * If the property value doesn't exist or isn't a valid double, def is returned.
+   * @param propertyName the property name
+   * @return the value for the provided property name, as a double, or def it is missing
+   */
+  public double getDoubleProperty(final String propertyName, final double def) {
+    final int pos = indexOfProperty(propertyName);
+    if (pos >= 0) {
+      try {
+        return Double.valueOf(properties.get(pos + 1));
+      } catch (final NumberFormatException e) {
+      }
+    }
+    return def;
+  }
+
+  /**
+   * Gets the property value for the provided property name, as a boolean.
+   * If the property value doesn't exist, def is returned.
+   * @param propertyName the property name
+   * @return the value for the provided property name, as a boolean, or def it is missing
+   */
+  public boolean getBooleanProperty(final String propertyName, final boolean def) {
+    final int pos = indexOfProperty(propertyName);
+    if (pos >= 0) {
+      return Boolean.valueOf(properties.get(pos + 1));
+    }
+    return def;
+  }
+
+  /**
+   * Sets the property value for the provided property name.
+   * @param propertyName the property name
+   * @param propertyValue the (new) property value
+   */
+  public void setProperty(final String propertyName, final String propertyValue) {
+    final int pos = indexOfProperty(propertyName);
+    if (pos >= 0) {
+      properties.set(pos + 1, propertyValue);
+    } else {
+      if (properties == null) {
+        properties = new ArrayList<>();
+      }
+      // add the property name
+      properties.add(propertyName);
+      // and the value
+      properties.add(propertyValue);
+    }
+  }
+
+  /**
+   * Convenience method for setting integer property.
+   * @param propertyName the property name
+   * @param propertyValue the (new) property value
+   */
+  public void setIntegerProperty(final String propertyName, final int value) {
+    setProperty(propertyName, Integer.toString(value));
+  }
+
+  /**
+   * Convenience method for setting integer property.
+   * @param propertyName the property name
+   * @param propertyValue the (new) property value
+   */
+  public void setDoubleProperty(final String propertyName, final double value) {
+    setProperty(propertyName, Double.toString(value));
+  }
+
+  /**
+   * Convenience method for setting boolean property.
+   * @param propertyName the property name
+   * @param propertyValue the (new) property value
+   */
+  public void setBooleanProperty(final String propertyName, final boolean value) {
+    setProperty(propertyName, Boolean.toString(value));
+  }
+
+  /**
+   * Removes the property with the provided name.
+   * @param propertyName the property to remove.
+   */
+  public void removeProperty(final String propertyName) {
+    final int pos = indexOfProperty(propertyName);
+    if (pos >= 0) {
+      // remove the property value
+      properties.remove(pos + 1);
+      // and the name
+      properties.remove(pos);
+      if (properties.isEmpty()) {
+        properties = null;
+      }
+    }
+  }
+}
diff --git a/simpleexample2/core/src/main/java/simpleex/core/README.md b/simpleexample2/core/src/main/java/simpleex/core/README.md
index c49c61ac1b36d020f77a4836e7eee24ecfe35a91..a7eebc1ade2c1175d271d9b3187518829171335e 100644
--- a/simpleexample2/core/src/main/java/simpleex/core/README.md
+++ b/simpleexample2/core/src/main/java/simpleex/core/README.md
@@ -2,8 +2,9 @@
 
 Domenelaget utgjøres av en samling av geo-lokasjoner representert vha. to klasse:
 
-- LatLong - en geo-lokasjon, representert vha. lengde og breddegrad
-- LatLongs - en samling LatLong-objekter
+- **LatLong** - en geo-lokasjon, representert vha. lengde og breddegrad
+- **LatLongs** - en samling LatLong-objekter
+- **MetaData** - tags og properties (nøkkel-verdi-par) som kan knyttes til **LatLong**-objekter
 
 ```plantuml
 class LatLong {
@@ -12,4 +13,6 @@ class LatLong {
 }
 class LatLongs
 LatLongs *--> "*" LatLong: "latLongs"
+class MetaData
+LatLong *--> "1" MetaData: "metaData"
 ```
diff --git a/simpleexample2/core/src/main/java/simpleex/json/LatLongDeserializer.java b/simpleexample2/core/src/main/java/simpleex/json/LatLongDeserializer.java
index 37636474cb2238d23ce69fac1df0274ee569d3d3..deaab616c7f4918c49dfb7d1e7ffbcdc3d6ca5cd 100644
--- a/simpleexample2/core/src/main/java/simpleex/json/LatLongDeserializer.java
+++ b/simpleexample2/core/src/main/java/simpleex/json/LatLongDeserializer.java
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.io.IOException;
 import simpleex.core.LatLong;
+import simpleex.core.MetaData;
 
 /**
  * JSON serializer for LatLong.
@@ -36,7 +37,24 @@ public class LatLongDeserializer extends JsonDeserializer<LatLong> {
       final ObjectNode objectNode = (ObjectNode) jsonNode;
       final double latitude = objectNode.get(LatLongSerializer.LATITUDE_FIELD_NAME).asDouble();
       final double longitude = objectNode.get(LatLongSerializer.LONGITUDE_FIELD_NAME).asDouble();
-      return new LatLong(latitude, longitude);
+      final LatLong latLon = new LatLong(latitude, longitude);
+      if (objectNode.has(LatLongSerializer.META_DATA_FIELD_NAME)) {
+        final ObjectNode metaDataNode = (ObjectNode) objectNode.get(LatLongSerializer.META_DATA_FIELD_NAME);
+        final MetaData metaData = latLon.getMetaData();
+        if (metaDataNode.has(LatLongSerializer.TAGS_FIELD_NAME)) {
+          for (final JsonNode tagNode : (ArrayNode) metaDataNode.get(LatLongSerializer.TAGS_FIELD_NAME)) {
+            metaData.addTags(tagNode.asText());
+          }
+        }
+        if (metaDataNode.has(LatLongSerializer.PROPERTIES_FIELD_NAME)) {
+          for (final JsonNode propertyNode : (ArrayNode) metaDataNode.get(LatLongSerializer.PROPERTIES_FIELD_NAME)) {
+            final String propertyName = (propertyNode instanceof ArrayNode ? ((ArrayNode) propertyNode).get(0) : ((ObjectNode) propertyNode).get(LatLongSerializer.PROPERTIES_NAME_FIELD_NAME)).asText();
+            final String propertyValue = (propertyNode instanceof ArrayNode ? ((ArrayNode) propertyNode).get(1) : ((ObjectNode) propertyNode).get(LatLongSerializer.PROPERTIES_VALUE_FIELD_NAME)).asText();
+            metaData.setProperty(propertyName, propertyValue);
+          }
+        }
+      }
+      return latLon;
     } else if (jsonNode instanceof ArrayNode) {
       final ArrayNode locationArray = (ArrayNode) jsonNode;
       if (locationArray.size() == ARRAY_JSON_NODE_SIZE) {
diff --git a/simpleexample2/core/src/main/java/simpleex/json/LatLongSerializer.java b/simpleexample2/core/src/main/java/simpleex/json/LatLongSerializer.java
index 59dfeb6fb57eccbacf6f91b8c16fb0d44d7c2c9a..d4d15425136199d4a1630d90530cdd0058cdc5f3 100644
--- a/simpleexample2/core/src/main/java/simpleex/json/LatLongSerializer.java
+++ b/simpleexample2/core/src/main/java/simpleex/json/LatLongSerializer.java
@@ -4,12 +4,19 @@ import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
 import java.io.IOException;
+import java.util.Iterator;
 import simpleex.core.LatLong;
+import simpleex.core.MetaData;
 
 public class LatLongSerializer extends JsonSerializer<LatLong> {
 
   public static final String LONGITUDE_FIELD_NAME = "longitude";
   public static final String LATITUDE_FIELD_NAME = "latitude";
+  public static final String META_DATA_FIELD_NAME = "metaData";
+  public static final String TAGS_FIELD_NAME = "tags";
+  public static final String PROPERTIES_FIELD_NAME = "properties";
+  public static final String PROPERTIES_NAME_FIELD_NAME = "name";
+  public static final String PROPERTIES_VALUE_FIELD_NAME = "value";
 
   @Override
   public void serialize(final LatLong latLon, final JsonGenerator jsonGen,
@@ -19,6 +26,38 @@ public class LatLongSerializer extends JsonSerializer<LatLong> {
     jsonGen.writeNumber(latLon.getLatitude());
     jsonGen.writeFieldName(LONGITUDE_FIELD_NAME);
     jsonGen.writeNumber(latLon.getLongitude());
+
+    // serialize meta-data
+    if (latLon.hasMetaData()) {
+      jsonGen.writeFieldName(META_DATA_FIELD_NAME);
+      jsonGen.writeStartObject();
+      final MetaData metaData = latLon.getMetaData();
+      final Iterator<String> tags = metaData.tags();
+      if (tags.hasNext()) {
+        jsonGen.writeFieldName(TAGS_FIELD_NAME);
+        jsonGen.writeStartArray();
+        while (tags.hasNext()) {
+          jsonGen.writeString(tags.next());
+        }
+        jsonGen.writeEndArray();
+      }
+      final Iterator<String> propertyNames = metaData.propertyNames();
+      if (propertyNames.hasNext()) {
+        jsonGen.writeFieldName(PROPERTIES_FIELD_NAME);
+        jsonGen.writeStartArray();
+        while (propertyNames.hasNext()) {
+          jsonGen.writeStartObject();
+          jsonGen.writeFieldName(PROPERTIES_NAME_FIELD_NAME);
+          final String propertyName = propertyNames.next();
+          jsonGen.writeString(propertyName);
+          jsonGen.writeFieldName(PROPERTIES_VALUE_FIELD_NAME);
+          jsonGen.writeString(metaData.getProperty(propertyName));
+          jsonGen.writeEndObject();
+        }
+        jsonGen.writeEndArray();
+      }
+      jsonGen.writeEndObject();
+    }
     jsonGen.writeEndObject();
   }
 }
diff --git a/simpleexample2/core/src/test/java/simpleex/core/LatLongTest.java b/simpleexample2/core/src/test/java/simpleex/core/LatLongTest.java
index 683577453314caf827d79a3e4d22fa0a7264f8a1..a3822dceeccd797df72edc302d34ffee91b7dd6d 100644
--- a/simpleexample2/core/src/test/java/simpleex/core/LatLongTest.java
+++ b/simpleexample2/core/src/test/java/simpleex/core/LatLongTest.java
@@ -68,4 +68,18 @@ public class LatLongTest {
   private void checkDistance(final double d, final double lower, final double upper) {
     Assert.assertTrue(d + " isn't between " + lower + " and " + upper, d <= upper && d >= lower);
   }
+
+  @Test
+  public void testHasGetMetaData() {
+    final LatLong latLong = new LatLong(63.0, 10.0);
+    Assert.assertFalse(latLong.hasMetaData());
+    final MetaData metaData = latLong.getMetaData();
+    Assert.assertNotNull(metaData);
+    Assert.assertFalse(latLong.hasMetaData());
+    metaData.addTags("aTag");
+    Assert.assertTrue(latLong.hasMetaData());
+    Assert.assertSame(metaData, latLong.getMetaData());
+    metaData.removeTags("aTag");
+    Assert.assertFalse(latLong.hasMetaData());
+  }
 }
diff --git a/simpleexample2/core/src/test/java/simpleex/core/MetaDataTest.java b/simpleexample2/core/src/test/java/simpleex/core/MetaDataTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e7843c2922b4f0ec66dfc64fd6abd4e9150c43d
--- /dev/null
+++ b/simpleexample2/core/src/test/java/simpleex/core/MetaDataTest.java
@@ -0,0 +1,135 @@
+package simpleex.core;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MetaDataTest {
+
+  private MetaData metaData;
+
+  @Before
+  public void setUp() {
+    metaData = new MetaData();
+  }
+
+  @Test
+  public void testHasTags() {
+    Assert.assertTrue(metaData.hasTags());
+    Assert.assertFalse(metaData.hasTags("aTag"));
+
+    metaData.addTags("aTag", "bTag");
+    Assert.assertTrue(metaData.hasTags());
+    Assert.assertTrue(metaData.hasTags("aTag"));
+    Assert.assertFalse(metaData.hasTags("aTag", "cTag"));
+
+    metaData.removeTags("aTag");
+    Assert.assertTrue(metaData.hasTags());
+    Assert.assertFalse(metaData.hasTags("aTag"));
+    Assert.assertTrue(metaData.hasTags("bTag"));
+  }
+
+  // relies on a certain order
+  private void check(final Iterator<String> it, final String... ss) {
+    final Iterator<String> it1 = Arrays.asList(ss).iterator();
+    while (it1.hasNext() && it.hasNext()) {
+      Assert.assertEquals(it1.next(), it.next());
+    }
+    Assert.assertEquals(it1.hasNext(), it.hasNext());
+  }
+
+  // relies on a certain order
+  private void checkTags(final String... tags) {
+    check(metaData.tags(), tags);
+  }
+
+  @Test
+  public void testMetaData() {
+    Assert.assertTrue(metaData.isEmpty());
+    checkTags();
+  }
+
+  @Test
+  public void testSetTags() {
+    metaData.setTags("aTag", "bTag");
+    checkTags("aTag", "bTag");
+    metaData.setTags("cTag", "bTag");
+    checkTags("cTag", "bTag");
+    metaData.setTags();
+    checkTags();
+  }
+
+  @Test
+  public void testAddRemoveTags() {
+    metaData.addTags("aTag", "bTag");
+    checkTags("aTag", "bTag");
+    metaData.addTags("cTag");
+    checkTags("aTag", "bTag", "cTag");
+    metaData.removeTags("bTag");
+    checkTags("aTag", "cTag");
+    metaData.removeTags("cTag");
+    checkTags("aTag");
+    metaData.removeTags("aTag");
+    Assert.assertTrue(metaData.isEmpty());
+  }
+
+  @Test
+  public void testHasProperty() {
+    Assert.assertFalse(metaData.hasProperty("aProp"));
+    metaData.setProperty("aProp", "aValue");
+    Assert.assertTrue(metaData.hasProperty("aProp"));
+  }
+
+  @Test
+  public void testGetSetProperty() {
+    metaData.setProperty("aProp", "aValue");
+    Assert.assertEquals("aValue", metaData.getProperty("aProp"));
+    metaData.setProperty("bProp", "bValue");
+    Assert.assertEquals("bValue", metaData.getProperty("bProp"));
+    metaData.setProperty("aProp", "anotherValue");
+    Assert.assertEquals("anotherValue", metaData.getProperty("aProp"));
+
+    Assert.assertEquals(-1, metaData.getIntegerProperty("iProp", -1));
+    metaData.setProperty("iProp", "notAnInteger");
+    Assert.assertEquals(-1, metaData.getIntegerProperty("dProp", -1));
+    metaData.setIntegerProperty("iProp", 42);
+    Assert.assertEquals(42, metaData.getIntegerProperty("iProp", -1));
+
+    Assert.assertEquals(-1.0, metaData.getDoubleProperty("dProp", -1.0), 0.0);
+    metaData.setProperty("dProp", "notADouble");
+    Assert.assertEquals(-1.0, metaData.getDoubleProperty("dProp", -1.0), 0.0);
+    metaData.setDoubleProperty("dProp", 42.0);
+    Assert.assertEquals(42.0, metaData.getDoubleProperty("dProp", -1.0), 0.0);
+
+    Assert.assertEquals(false, metaData.getBooleanProperty("bProp", false));
+    metaData.setProperty("bProp", "notABoolean");
+    Assert.assertEquals(false, metaData.getBooleanProperty("bProp", true));
+    metaData.setBooleanProperty("bProp", true);
+    Assert.assertEquals(true, metaData.getBooleanProperty("bProp", false));
+  }
+
+  @Test
+  public void testSetRemoveProperty() {
+    metaData.setProperty("aProp", "aValue");
+    Assert.assertTrue(metaData.hasProperty("aProp"));
+    metaData.removeProperty("aProp");
+    Assert.assertFalse(metaData.hasProperty("aProp"));
+    Assert.assertTrue(metaData.isEmpty());
+  }
+
+  // relies on a certain order
+  private void checkPropertyNames(final String... propertyNames) {
+    check(metaData.propertyNames(), propertyNames);
+  }
+
+  @Test
+  public void testPropertyNames() {
+    checkPropertyNames();
+    metaData.setProperty("aProp", "aValue");
+    checkPropertyNames("aProp");
+    metaData.removeProperty("aProp");
+    checkPropertyNames();
+  }
+}
diff --git a/simpleexample2/core/src/test/java/simpleex/json/LatLongsJsonTest.java b/simpleexample2/core/src/test/java/simpleex/json/LatLongsJsonTest.java
index 079cab29ef6164db476c972c9d3d59ec70de72df..cf1d8e99bc68c892ab402a2e188abbb66e09e0d5 100644
--- a/simpleexample2/core/src/test/java/simpleex/json/LatLongsJsonTest.java
+++ b/simpleexample2/core/src/test/java/simpleex/json/LatLongsJsonTest.java
@@ -1,10 +1,14 @@
 package simpleex.json;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Arrays;
+import java.util.Iterator;
 import org.junit.Assert;
 import org.junit.Test;
 import simpleex.core.LatLong;
 import simpleex.core.LatLongs;
+import simpleex.core.MetaData;
 
 public class LatLongsJsonTest {
 
@@ -43,4 +47,66 @@ public class LatLongsJsonTest {
     Assert.assertEquals(latLong1(), latLongs.getLatLong(0));
     Assert.assertEquals(latLong2(), latLongs.getLatLong(1));
   }
+
+  @Test
+  public void testLatLongMetaDataSerialization() throws Exception {
+    final LatLong latLong = latLong1();
+    final MetaData metaData = latLong.getMetaData();
+    metaData.addTags("aTag", "bTag");
+    metaData.setProperty("aProperty", "aValue");
+    final String actualJson = objectMapper.writeValueAsString(latLong);
+    final String expectedJson = "{\"latitude\":63.1,\"longitude\":12.3,"
+        + "\"metaData\":{\"tags\":[\"aTag\",\"bTag\"],\"properties\":[{\"name\":\"aProperty\",\"value\":\"aValue\"}]}}";
+    assertEqualsIgnoreWhitespace(expectedJson, actualJson);
+  }
+
+  @Test
+  public void testLatLongsMetaDataSerialization() {
+    final LatLong latLong = latLong1();
+    final MetaData metaData = latLong.getMetaData();
+    metaData.addTags("aTag", "bTag");
+    metaData.setProperty("aProperty", "aValue");
+    final LatLongs latLongs = new LatLongs(latLong);
+    try {
+      final String actualJson = objectMapper.writeValueAsString(latLongs);
+      final String expectedJson = "[{\"latitude\":63.1,\"longitude\":12.3,"
+          + "\"metaData\":{\"tags\":[\"aTag\",\"bTag\"],\"properties\":[{\"name\":\"aProperty\",\"value\":\"aValue\"}]}}]";
+      assertEqualsIgnoreWhitespace(expectedJson, actualJson);
+    } catch (final JsonProcessingException e) {
+      Assert.fail();
+    } catch (final Exception e) {
+      Assert.fail();
+    }
+  }
+
+  @Test
+  public void testLatLongsMetaDataDeserialization() throws Exception {
+    final String json = "[{\"latitude\":63.1,\"longitude\":12.3,"
+        + "\"metaData\":{\"tags\":[\"aTag\",\"bTag\"],\"properties\":[{\"name\":\"aProperty\",\"value\":\"aValue\"}]}}]";
+    final LatLongs latLongs = objectMapper.readValue(json, LatLongs.class);
+    Assert.assertEquals(1, latLongs.getLatLongCount());
+    Assert.assertTrue(latLongs.getLatLong(0).hasMetaData());
+  }
+
+  // relies on a certain order
+  private void check(final Iterator<String> it, final String... ss) {
+    final Iterator<String> it1 = Arrays.asList(ss).iterator();
+    while (it1.hasNext() && it.hasNext()) {
+      Assert.assertEquals(it1.next(), it.next());
+    }
+    Assert.assertEquals(it1.hasNext(), it.hasNext());
+  }
+
+  @Test
+  public void testLatLongMetaDataDeserialization() throws Exception {
+    final String json = "{\"latitude\":63.1,\"longitude\":12.3,"
+        + "\"metaData\":{\"tags\":[\"aTag\",\"bTag\"],\"properties\":[{\"name\":\"aProperty\",\"value\":\"aValue\"},[\"bProperty\",\"bValue\"]]}}";
+    final LatLong latLong = objectMapper.readValue(json, LatLong.class);
+    final MetaData metaData = latLong.getMetaData();
+    Assert.assertTrue(metaData.hasTags("aTag", "bTag"));
+    Assert.assertEquals("aValue", metaData.getProperty("aProperty"));
+    Assert.assertEquals("bValue", metaData.getProperty("bProperty"));
+    check(metaData.tags(), "aTag", "bTag");
+    check(metaData.propertyNames(), "aProperty", "bProperty");
+  }
 }