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"); + } }