/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2010, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.geojson; import java.io.ByteArrayOutputStream; import java.io.StringWriter; import java.util.List; import org.geotools.data.DataUtilities; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.feature.DefaultFeatureCollection; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geojson.feature.FeatureJSON; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.junit.Test; import org.opengis.feature.Feature; import org.opengis.feature.GeometryAttribute; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.io.WKTReader; /** * * * @source $URL$ */ public class FeatureJSONTest extends GeoJSONTestSupport { FeatureJSON fjson = new FeatureJSON(); SimpleFeatureType featureType; SimpleFeatureBuilder fb; @Override protected void setUp() throws Exception { super.setUp(); SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); tb.setName("feature"); tb.setSRS("EPSG:4326"); tb.add("int", Integer.class); tb.add("double", Double.class); tb.add("string", String.class); tb.add("geometry", Geometry.class); featureType = tb.buildFeatureType(); fb = new SimpleFeatureBuilder(featureType); } public void testFeatureWrite() throws Exception { StringWriter writer = new StringWriter(); fjson.writeFeature(feature(1), writer); assertEquals(strip(featureText(1)), writer.toString()); } public void testWriteReadNoProperties() throws Exception { SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); tb.add("geom", Point.class, CRS.decode("EPSG:4326")); tb.add("name", String.class); tb.add("quantity", Integer.class); tb.setName("outbreak"); SimpleFeatureType schema = tb.buildFeatureType(); SimpleFeatureBuilder fb = new SimpleFeatureBuilder(schema); fb.add(new WKTReader().read("POINT(10 20)")); SimpleFeature feature = fb.buildFeature("outbreak.1"); FeatureJSON fj = new FeatureJSON(); ByteArrayOutputStream os = new ByteArrayOutputStream(); fj.writeFeature(feature, os); String json = os.toString(); // here it would break because the written json was incorrect SimpleFeature feature2 = fj.readFeature(json); assertNotNull(feature2); //assertEquals(feature.getID(), feature2.getID()); } public void testFeatureRead() throws Exception { SimpleFeature f1 = feature(1); SimpleFeature f2 = fjson.readFeature(reader(strip(featureText(1)))); assertEqualsLax(f1, f2); } public void testFeatureWithGeometryCollectionRead() throws Exception { String json = strip("{" + " 'type':'Feature'," + " 'geometry': {" + " 'type':'GeometryCollection'," + " 'geometries':[{" + " 'type':'Point','coordinates':[4,6]" + " },{" + " 'type':'LineString','coordinates':[[4,6],[7,10]]" + " }" + " ]" + " }," + " 'properties':{" + " 'name':'Name123'," + " 'label':'Label321'," + " 'roles':'[1,2,3]'" + " }," + " 'id':'fid-7205cfc1_138e7ce8900_-7ffe'" + "}"); SimpleFeature f1 = fjson.readFeature(json); assertNotNull(f1.getDefaultGeometry()); GeometryCollection gc = (GeometryCollection) f1.getDefaultGeometry(); assertEquals(2, gc.getNumGeometries()); WKTReader wkt = new WKTReader(); assertTrue(wkt.read("POINT (4 6)").equals(gc.getGeometryN(0))); assertTrue(wkt.read("LINESTRING (4 6, 7 10)").equals(gc.getGeometryN(1))); assertEquals("fid-7205cfc1_138e7ce8900_-7ffe", f1.getID()); assertEquals("Name123", f1.getAttribute("name")); assertEquals("Label321", f1.getAttribute("label")); assertEquals("[1,2,3]", f1.getAttribute("roles")); } public void testFeatureWithGeometryCollectionRead2() throws Exception { String json = strip("{"+ " 'type':'Feature',"+ " 'geometry':{"+ " 'type':'GeometryCollection',"+ " 'geometries':["+ " {"+ " 'type':'Polygon',"+ " 'coordinates':[[[-28.1107, 142.998], [-28.1107, 148.623], [-30.2591, 148.623], [-30.2591, 142.998], [-28.1107, 142.998]]]"+ " },"+ " {"+ " 'type':'Polygon',"+ " 'coordinates':[[[-27.1765, 142.998], [-25.6811, 146.4258], [-27.1765, 148.5352], [-27.1765, 142.998]]]"+ " }"+ " ]"+ " },"+ " 'properties':{"+ " 'name':'',"+ " 'caseSN':'x_2000a',"+ " 'siteNum':2"+ " },"+ " 'id':'fid-397164b3_13880d348b9_-7a5c'"+ "}"); SimpleFeature f1 = fjson.readFeature(json); assertNotNull(f1.getDefaultGeometry()); GeometryCollection gc = (GeometryCollection) f1.getDefaultGeometry(); assertEquals(2, gc.getNumGeometries()); WKTReader wkt = new WKTReader(); assertTrue(wkt.read("POLYGON ((-28.1107 142.998, -28.1107 148.623, -30.2591 148.623, -30.2591 142.998, -28.1107 142.998))").equals(gc.getGeometryN(0))); assertTrue(wkt.read("POLYGON((-27.1765 142.998, -25.6811 146.4258, -27.1765 148.5352, -27.1765 142.998))").equals(gc.getGeometryN(1))); assertEquals("fid-397164b3_13880d348b9_-7a5c", f1.getID()); assertEquals("", f1.getAttribute("name")); assertEquals("x_2000a", f1.getAttribute("caseSN")); assertEquals(2l, f1.getAttribute("siteNum")); } public void testFeatureWithRegularGeometryAttributeRead() throws Exception { SimpleFeature f = fjson.readFeature(reader(strip("{" + " 'type': 'Feature'," + " 'geometry': {" + " 'type': 'Point'," + " 'coordinates': [0.1, 0.1]," + " }," + " 'properties': {" + " 'int': 1," + " 'double': 0.1," + " 'string': 'one'," + " 'otherGeometry': {" + " 'type': 'LineString'," + " 'coordinates': [[1.1, 1.2], [1.3, 1.4]]" + " }"+ " }," + " 'id': 'feature.0'" + " }"))); assertNotNull(f); assertTrue(f.getDefaultGeometry() instanceof Point); Point p = (Point) f.getDefaultGeometry(); assertEquals(0.1, p.getX(), 0.1); assertEquals(0.1, p.getY(), 0.1); assertTrue(f.getAttribute("otherGeometry") instanceof LineString); assertTrue(new GeometryFactory().createLineString(new Coordinate[]{ new Coordinate(1.1, 1.2), new Coordinate(1.3, 1.4)}).equals((LineString)f.getAttribute("otherGeometry"))); assertEquals(1, ((Number)f.getAttribute("int")).intValue()); assertEquals(0.1, ((Number)f.getAttribute("double")).doubleValue()); assertEquals("one", f.getAttribute("string")); } public void testFeatureWithDefaultGeometryEqualsNullRead() throws Exception { SimpleFeature f = fjson.readFeature(reader(strip("{" + " 'type': 'Feature'," + " 'geometry': null," + " 'properties': {" + " 'int': 1," + " 'double': 0.1," + " 'string': 'one'" + " }," + " 'id': 'feature.0'" + " }"))); assertNotNull(f); assertTrue(f.getDefaultGeometry() == null); assertEquals(1, ((Number)f.getAttribute("int")).intValue()); assertEquals(0.1, ((Number)f.getAttribute("double")).doubleValue()); assertEquals("one", f.getAttribute("string")); } public void testFeatureWithRegularGeometryAttributeNoDefaultGeometryRead() throws Exception { SimpleFeature f = fjson.readFeature(reader(strip("{" + " 'type': 'Feature'," + " 'properties': {" + " 'int': 1," + " 'double': 0.1," + " 'string': 'one'," + " 'otherGeometry': {" + " 'type': 'LineString'," + " 'coordinates': [[1.1, 1.2], [1.3, 1.4]]" + " }"+ " }," + " 'id': 'feature.0'" + " }"))); assertNotNull(f); assertTrue(f.getDefaultGeometry() instanceof LineString); LineString l = (LineString) f.getDefaultGeometry(); assertTrue(new GeometryFactory().createLineString(new Coordinate[]{ new Coordinate(1.1, 1.2), new Coordinate(1.3, 1.4)}).equals(l)); assertTrue(f.getAttribute("otherGeometry") instanceof LineString); assertTrue(new GeometryFactory().createLineString(new Coordinate[]{ new Coordinate(1.1, 1.2), new Coordinate(1.3, 1.4)}).equals((LineString)f.getAttribute("otherGeometry"))); assertEquals(1, ((Number)f.getAttribute("int")).intValue()); assertEquals(0.1, ((Number)f.getAttribute("double")).doubleValue()); assertEquals("one", f.getAttribute("string")); } public void testFeatureWithBoundsWrite() throws Exception { String json = "{" + " 'type': 'Feature'," + " 'bbox': [1.1, 1.1, 1.1, 1.1], " + " 'geometry': {" + " 'type': 'Point'," + " 'coordinates': [1.1, 1.1]" + " }," + " 'properties': {" + " 'int': 1," + " 'double': 1.1," + " 'string': 'one'" + " }," + " 'id': 'feature.1'" + " }"; fjson.setEncodeFeatureBounds(true); assertEquals(strip(json), fjson.toString(feature(1))); } public void testFeatureWithCRSWrite() throws Exception { fjson.setEncodeFeatureCRS(true); assertEquals(strip(featureWithCRSText()), fjson.toString(feature(1))); } public void testFeatureNoGeometryWrite() throws Exception { String json = "{" + " 'type': 'Feature'," + " 'properties': {" + " 'foo': 'FOO'" + " }," + " 'id': 'feature.foo'" + " }"; SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); tb.setName("nogeom"); tb.add("foo", String.class); SimpleFeatureType ft = tb.buildFeatureType(); SimpleFeatureBuilder b = new SimpleFeatureBuilder(ft); b.add("FOO"); SimpleFeature f = b.buildFeature("feature.foo"); assertEquals(strip(json), fjson.toString(f)); } String featureWithCRSText() { String json = "{" + " 'type': 'Feature'," + " 'crs': {" + " 'type': 'name'," + " 'properties': {" + " 'name': 'EPSG:4326'" + " }" + " }, " + " 'geometry': {" + " 'type': 'Point'," + " 'coordinates': [1.1, 1.1]" + " }," + " 'properties': {" + " 'int': 1," + " 'double': 1.1," + " 'string': 'one'" + " }," + " 'id': 'feature.1'" + " }"; return json; } public void testFeatureWithCRSRead() throws Exception { SimpleFeature f = fjson.readFeature(reader(strip(featureWithCRSText()))); assertTrue(CRS.equalsIgnoreMetadata(CRS.decode("EPSG:4326"), f.getFeatureType().getCoordinateReferenceSystem())); } String featureWithBBOXText() { String json = "{" + " 'type': 'Feature'," + " 'bbox': [1.1, 1.1, 1.1, 1.1]," + " 'geometry': {" + " 'type': 'Point'," + " 'coordinates': [1.1, 1.1]" + " }," + " 'properties': {" + " 'int': 1," + " 'double': 1.1," + " 'string': 'one'" + " }," + " 'id': 'feature.1'" + " }"; return json; } public void testFeatureWithBBOXRead() throws Exception { SimpleFeature f = fjson.readFeature(reader(strip(featureWithBBOXText()))); assertEquals(1.1, f.getBounds().getMinX(), 0.1d); assertEquals(1.1, f.getBounds().getMaxX(), 0.1d); assertEquals(1.1, f.getBounds().getMinY(), 0.1d); assertEquals(1.1, f.getBounds().getMaxY(), 0.1d); } String featureWithBoundedByAttributeText() { String json = "{" + " 'type': 'Feature'," + " 'geometry': {" + " 'type': 'Point'," + " 'coordinates': [1.1, 1.1]" + " }," + " 'properties': {" + " 'boundedBy': [-1.2, -1.3, 1.2, 1.3]," + " 'int': 1," + " 'double': 1.1," + " 'string': 'one'" + " }," + " 'id': 'feature.1'" + " }"; return json; } SimpleFeature featureWithBoundedByAttribute() { SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); tb.setName("feature"); tb.add("geometry", Point.class); tb.add("boundedBy", Envelope.class); tb.add("int", Integer.class); tb.add("double", Double.class); tb.add("string", String.class); SimpleFeatureBuilder b = new SimpleFeatureBuilder(tb.buildFeatureType()); b.add(new GeometryFactory().createPoint(new Coordinate(1.1,1.1))); b.add(new Envelope(-1.2, 1.2, -1.3, 1.3)); b.add(1); b.add(1.1); b.add("one"); return b.buildFeature("feature.1"); } public void testFeatureWithBoundedByAttributeRead() throws Exception { SimpleFeature f = fjson.readFeature(reader(strip(featureWithBoundedByAttributeText()))); List l = (List) f.getAttribute("boundedBy"); assertEquals(-1.2, (Double) l.get(0), 0.1d); assertEquals(-1.3, (Double) l.get(1), 0.1d); assertEquals(1.2, (Double) l.get(2), 0.1d); assertEquals(1.3, (Double) l.get(3), 0.1d); } public void testFeatureWithoutPropertiesRead() throws Exception { SimpleFeature f = fjson.readFeature(reader(strip(featureWithoutPropertiesText()))); assertEquals(1, f.getFeatureType().getAttributeCount()); assertEquals("geometry", f.getFeatureType().getDescriptor(0).getLocalName()); assertEquals(1.2, ((Point)f.getDefaultGeometry()).getX()); assertEquals(3.4, ((Point)f.getDefaultGeometry()).getY()); } String featureWithoutPropertiesText() { String json = "{" + " 'type': 'Feature'," + " 'geometry': {" + " 'type': 'Point'," + " 'coordinates': [1.2, 3.4]" + " }," + " 'id': 'feature.1'" + " }"; return json; } public void testFeatureWithGeometryAfterPropertiesRead() throws Exception { SimpleFeature f1 = feature(1); SimpleFeature f2 = fjson.readFeature(reader(strip(featureTextWithGeometryAfterProperties(1)))); assertEqualsLax(f1, f2); } String featureTextWithGeometryAfterProperties(int val) { String text = "{" + " 'type': 'Feature'," + "' properties': {" + " 'int': " + val + "," + " 'double': " + (val + 0.1) + "," + " 'string': '" + toString(val) + "'" + " }," + " 'geometry': {" + " 'type': 'Point'," + " 'coordinates': [" + (val+0.1) + "," + (val+0.1) + "]" + " }, " + " 'id':'feature." + val + "'" + "}"; return text; } public void testFeatureWithBoundedByAttributeWrite() throws Exception { StringWriter writer = new StringWriter(); fjson.writeFeature(featureWithBoundedByAttribute(), writer); assertEquals(strip(featureWithBoundedByAttributeText()), writer.toString()); } public void testFeatureCollectionWrite() throws Exception { StringWriter writer = new StringWriter(); fjson.writeFeatureCollection(collection(), writer); assertEquals(strip(collectionText()), writer.toString()); } public void testFeatureCollectionRead() throws Exception { FeatureCollection actual = fjson.readFeatureCollection(reader(strip(collectionText()))); assertNotNull(actual); FeatureCollection expected = collection(); assertEquals(expected.size(), actual.size()); FeatureIterator a = actual.features(); FeatureIterator e = expected.features(); while(e.hasNext()) { assertTrue(a.hasNext()); assertEqualsLax((SimpleFeature)e.next(), (SimpleFeature) a.next()); } a.close(); e.close(); } public void testFeatureCollectionStreamBasic() throws Exception { testFeatureCollectionStream(false, false); } public void testFeatureCollectionStreamFull() throws Exception { testFeatureCollectionStream(true, true); } void testFeatureCollectionStream(boolean withBounds, boolean withCRS) throws Exception { FeatureIterator<SimpleFeature> features = fjson.streamFeatureCollection(reader(strip(collectionText(withBounds, withCRS)))); FeatureCollection expected = collection(); FeatureIterator e = expected.features(); while(e.hasNext()) { features.hasNext(); //ensure that hasNext() does not skip features assertTrue(features.hasNext()); assertEqualsLax((SimpleFeature)e.next(), features.next()); } features.close(); e.close(); } public void testFeatureCollectionWithBoundsWrite() throws Exception { fjson.setEncodeFeatureCollectionBounds(true); assertEquals(strip(collectionText(true, false)), fjson.toString(collection())); } public void testFeatureCollectionWithCRSWrite() throws Exception { fjson.setEncodeFeatureCollectionCRS(true); assertEquals(strip(collectionText(false, true)), fjson.toString(collection())); } public void testFeatureCollectionWithNonWGS84CRSWrite() throws Exception { String json = "{" + " 'type': 'FeatureCollection'," + " 'crs': {" + " 'type': 'name'," + " 'properties': {" + " 'name': 'EPSG:3857'" + " }" + " }," + " 'features': [" + " {" + " 'type': 'Feature'," + " 'geometry': {" + " 'type': 'Point', " + " 'coordinates': [2.003750834E7, 2.003750834E7]" + " }," + " 'properties': {" + " }," + " 'id': 'xyz.1'" + " }" + " ]" + "}"; SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); tb.add("geom", Point.class, CRS.decode("EPSG:3857")); tb.add("name", String.class); tb.setName("xyz"); SimpleFeatureType schema = tb.buildFeatureType(); DefaultFeatureCollection fc = new DefaultFeatureCollection(); SimpleFeatureBuilder fb = new SimpleFeatureBuilder(schema); fb.add(new WKTReader().read("POINT(20037508.34 20037508.34)")); fc.add(fb.buildFeature("xyz.1")); FeatureJSON fj = new FeatureJSON(); ByteArrayOutputStream os = new ByteArrayOutputStream(); fj.writeFeatureCollection(fc, os); assertEquals(strip(json), os.toString()); } public void testFeatureCollectionWithCRSRead() throws Exception { String json = collectionText(true, true); FeatureCollection fcol = fjson.readFeatureCollection(strip(collectionText(true, true))); assertNotNull(fcol.getSchema().getCoordinateReferenceSystem()); FeatureIterator it = fcol.features(); while(it.hasNext()) { assertNotNull(it.next().getType().getCoordinateReferenceSystem()); } } public void testFeatureCollectionWithMissingAttributeRead() throws Exception { String collectionText = collectionText(true, true, false, true, false); SimpleFeatureType ftype = fjson.readFeatureCollectionSchema((strip(collectionText)), false); assertNotNull(ftype.getDescriptor("double")); assertEquals(Double.class, ftype.getDescriptor("double").getType().getBinding()); assertNotNull(ftype.getDescriptor("int")); assertEquals(Long.class, ftype.getDescriptor("int").getType().getBinding()); assertNotNull(ftype.getDescriptor("string")); assertEquals(String.class, ftype.getDescriptor("string").getType().getBinding()); assertNotNull(ftype.getCoordinateReferenceSystem()); fjson.setFeatureType(ftype); SimpleFeatureCollection fcol = (SimpleFeatureCollection) fjson.readFeatureCollection((strip(collectionText))); assertEquals(ftype, fcol.getSchema()); FeatureIterator it = fcol.features(); while(it.hasNext()) { assertEquals(ftype, it.next().getType()); } } @Test public void testFeatureCollectionWithNullAttributeRead() throws Exception { String collectionText = collectionText(true, true, false, false, true); SimpleFeatureType ftype = fjson.readFeatureCollectionSchema((strip(collectionText)), true); System.out.println("type: " + ftype); assertEquals(4, ftype.getAttributeCount()); assertNotNull(ftype.getDescriptor("int")); assertEquals(Long.class, ftype.getDescriptor(1).getType().getBinding()); assertNotNull(ftype.getDescriptor("double")); assertEquals(Double.class, ftype.getDescriptor(2).getType().getBinding()); assertNotNull(ftype.getDescriptor("string")); assertEquals(String.class, ftype.getDescriptor(3).getType().getBinding()); assertNotNull(ftype.getCoordinateReferenceSystem()); fjson.setFeatureType(ftype); SimpleFeatureCollection fcol = (SimpleFeatureCollection) fjson.readFeatureCollection((strip(collectionText))); assertEquals(ftype, fcol.getSchema()); FeatureIterator it = fcol.features(); while(it.hasNext()) { assertEquals(ftype, it.next().getType()); } } public void testFeatureCollectionWithNullAttributeAllFeaturesRead() throws Exception { String collectionText = collectionText(true, true, false, false, false, true); SimpleFeatureType ftype = fjson.readFeatureCollectionSchema((strip(collectionText)), false); assertNotNull(ftype.getDescriptor("double")); // type defaults to String as all values were null assertEquals(String.class, ftype.getDescriptor("double").getType().getBinding()); assertNotNull(ftype.getDescriptor("int")); assertEquals(Long.class, ftype.getDescriptor("int").getType().getBinding()); assertNotNull(ftype.getDescriptor("string")); assertEquals(String.class, ftype.getDescriptor("string").getType().getBinding()); assertNotNull(ftype.getCoordinateReferenceSystem()); fjson.setFeatureType(ftype); SimpleFeatureCollection fcol = (SimpleFeatureCollection) fjson.readFeatureCollection((strip(collectionText))); assertEquals(ftype, fcol.getSchema()); FeatureIterator it = fcol.features(); while(it.hasNext()) { assertEquals(ftype, it.next().getType()); } } public void testFeatureCollectionWithCRSPostFeaturesRead() throws Exception { String json = collectionText(true, true); FeatureCollection fcol = fjson.readFeatureCollection(strip(collectionText(true, true, true, false, false))); assertNotNull(fcol.getSchema().getCoordinateReferenceSystem()); FeatureIterator it = fcol.features(); while(it.hasNext()) { assertNotNull(it.next().getType().getCoordinateReferenceSystem()); } } public void testFeatureCollectionWithTypePostFeaturesRead() throws Exception { String json = strip("{ " + " 'features' : [{ " +" 'geometry' : { 'coordinates' : [ 17.633333, 59.85 ], 'type' : 'Point' }," + " 'type' : 'Feature'," + " 'properties' : { 'name' : 'Station' }" + " }]," + " 'type' : 'FeatureCollection'" + "}"); FeatureCollection fcol = fjson.readFeatureCollection(json); FeatureIterator it = fcol.features(); assertTrue(it.hasNext()); SimpleFeature f = (SimpleFeature) it.next(); assertTrue(new WKTReader().read("POINT (17.633333 59.85)").equals((Geometry)f.getDefaultGeometry())); assertEquals("Station", f.getAttribute("name")); it.close(); } public void testEmptyFeatureCollection() throws Exception { String json = strip("{'type':'FeatureCollection','features':[]}"); FeatureCollection fcol = fjson.readFeatureCollection(json); assertNull(fcol.getSchema()); assertTrue(fcol.isEmpty()); } public void testCRSWrite() throws Exception { CoordinateReferenceSystem crs = CRS.decode("EPSG:4326"); StringWriter writer = new StringWriter(); fjson.writeCRS(crs, writer); assertEquals(strip(crsText()), writer.toString()); } public void testCRSRead() throws Exception { Object crs = fjson.readCRS(reader(strip(crsText()))); assertTrue(CRS.equalsIgnoreMetadata(CRS.decode("epsg:4326"), crs)); } public void testFeatureCollectionWithNullBoundsWrite() throws Exception { DefaultFeatureCollection features = new DefaultFeatureCollection() { @Override public ReferencedEnvelope getBounds() { return null; } }; features.add(feature(0)); String json = fjson.toString(features); } public void testFeatureCollectionWithNullGeometrySchemaRead() throws Exception { String json = strip( "{" + " 'type': 'FeatureCollection'," + " 'features': [" + " {" + " 'type': 'Feature'," + " 'geometry': null," + " 'properties': {" + " }," + " 'id': 'xyz.1'" + " }" + " ]" + "}"); SimpleFeatureType type = fjson.readFeatureCollectionSchema(json, true); assertNull(type.getGeometryDescriptor()); } public void testFeatureCollectionWithoutGeometrySchemaRead() throws Exception { String json = strip( "{" + " 'type': 'FeatureCollection'," + " 'features': [" + " {" + " 'type': 'Feature'," + " 'properties': {" + " }," + " 'id': 'xyz.1'" + " }" + " ]" + "}"); SimpleFeatureType type = fjson.readFeatureCollectionSchema(json, true); assertNull(type.getGeometryDescriptor()); } public void testFeatureCollectionConflictingTypesSchemaRead() throws Exception { String json = strip( "{" + " 'type': 'FeatureCollection'," + " 'features': [" + " {" + " 'type': 'Feature'," + " 'properties': {" + " 'prop': 1" + " }" + " }," + " {" + " 'type': 'Feature'," + " 'properties': {" + " 'prop': 'xyz'" + " }" + " }" + " ]" + "}"); try { fjson.readFeatureCollectionSchema(json, false); fail("Should have thrown IllegalStateException"); } catch (IllegalStateException e) { } } public void testFeatureCollectionWithoutGeometryReadWriteFromFeatureSource() throws Exception { String json = strip( "{" + " 'type': 'FeatureCollection'," + " 'features': [" + " {" + " 'type': 'Feature'," + " 'properties': {" + " }," + " 'id': 'xyz.1'" + " }" + " ]" + "}"); SimpleFeatureSource fs = DataUtilities.source(fjson.readFeatureCollection(json)); fjson.toString(fs.getFeatures()); } public void testFeatureCollectionConflictingButInterchangeableTypesSchemaRead() throws Exception { String json = strip( "{" + " 'type': 'FeatureCollection'," + " 'features': [" + " {" + " 'type': 'Feature'," + " 'properties': {" + " 'prop': 1" + " }" + " }," + " {" + " 'type': 'Feature'," + " 'properties': {" + " 'prop': 1.0" + " }" + " }" + " ]" + "}"); SimpleFeatureType type = fjson.readFeatureCollectionSchema(json, false); assertEquals(Double.class, type.getDescriptor("prop").getType().getBinding()); } public void testFeatureCollectionWithIdPropertyReadWrite() throws Exception { String json = strip( "{" + " 'type': 'FeatureCollection'," + " 'features': [" + " {" + " 'type': 'Feature'," + " 'properties': {" + " 'id': 'one'" + " }," + " 'id': 'xyz.1'" + " }" + " ]" + "}"); FeatureCollection fc = fjson.readFeatureCollection(json); assertNotNull(fc.getSchema().getDescriptor("id")); Feature feat = fc.features().next(); assertEquals("one", feat.getProperty("id").getValue()); assertEquals("xyz.1", feat.getIdentifier().getID()); ByteArrayOutputStream os = new ByteArrayOutputStream(); fjson.writeFeatureCollection(fc, os); assertEquals(json, os.toString()); } String crsText() { return "{" + " 'type': 'name',"+ " 'properties': {"+ " 'name': 'EPSG:4326'"+ " }"+ "}"; } SimpleFeature feature(int val) { fb.add(val); fb.add(val + 0.1); fb.add(toString(val)); fb.add(new GeometryFactory().createPoint(new Coordinate(val+0.1,val+0.1))); return fb.buildFeature("feature." + val); } SimpleFeature featureMissingAttribute(int val) { fb.add(val); fb.add(val + 0.1); fb.add(new GeometryFactory().createPoint(new Coordinate(val+0.1,val+0.1))); return fb.buildFeature("feature." + val); } SimpleFeature featureNullAttribute(int val) { fb.add(val); fb.add(null); fb.add(toString(val)); fb.add(new GeometryFactory().createPoint(new Coordinate(val+0.1,val+0.1))); return fb.buildFeature("feature." + val); } String featureText(int val) { return featureText(val, false, false); } String featureText(int val, boolean missingAttribute, boolean nullAttribute) { if (missingAttribute && nullAttribute) { throw new IllegalArgumentException("For tests, use only one of either missingAttribute or nullAttribute"); } String text = "{" + " 'type': 'Feature'," + " 'geometry': {" + " 'type': 'Point'," + " 'coordinates': [" + (val+0.1) + "," + (val+0.1) + "]" + " }, " + "' properties': {" + " 'int': " + val + "," + (missingAttribute ? "" : (nullAttribute ? (" 'double': null,") : ( " 'double': " + (val + 0.1) + ","))) + " 'string': '" + toString(val) + "'" + " }," + " 'id':'feature." + val + "'" + "}"; return text; } FeatureCollection collection() { DefaultFeatureCollection collection = new DefaultFeatureCollection(null, featureType); for (int i = 0; i < 3; i++) { collection.add(feature(i)); } return collection; } String collectionText() { return collectionText(false,false); } String collectionText(boolean withBounds, boolean withCRS) { return collectionText(withBounds, withCRS, false, false, false, false); } String collectionText(boolean withBounds, boolean withCRS, boolean crsAfter, boolean missingFirstFeatureAttribute, boolean nullFirstFeatureAttribute) { return collectionText(withBounds, withCRS, crsAfter, missingFirstFeatureAttribute, nullFirstFeatureAttribute, false); } String collectionText(boolean withBounds, boolean withCRS, boolean crsAfter, boolean missingFirstFeatureAttribute, boolean nullFirstFeatureAttribute, boolean nullAttributeAllFeatures) { StringBuffer sb = new StringBuffer(); sb.append("{'type':'FeatureCollection',"); if (withBounds) { FeatureCollection features = collection(); ReferencedEnvelope bbox = features.getBounds(); sb.append("'bbox': ["); sb.append(bbox.getMinX()).append(",").append(bbox.getMinY()).append(",") .append(bbox.getMaxX()).append(",").append(bbox.getMaxY()); sb.append("],"); } if (withCRS && !crsAfter) { sb.append("'crs': {"); sb.append(" 'type': 'name',"); sb.append(" 'properties': {"); sb.append(" 'name': 'EPSG:4326'"); sb.append(" }"); sb.append("},"); } sb.append("'features':["); if (nullAttributeAllFeatures) { // creates all features with a null attribute for (int i = 0; i < 3; i++) { sb.append(featureText(i, false, true)).append(","); } } else { // only the first feature will have a null or missing attribute sb.append(featureText(0, missingFirstFeatureAttribute, nullFirstFeatureAttribute)).append(","); for (int i = 1; i < 3; i++) { sb.append(featureText(i, false, false)).append(","); } } sb.setLength(sb.length()-1); sb.append("]"); if (withCRS && crsAfter) { sb.append(",'crs': {"); sb.append(" 'type': 'name',"); sb.append(" 'properties': {"); sb.append(" 'name': 'EPSG:4326'"); sb.append(" }"); sb.append("}"); } sb.append("}"); return sb.toString(); } public void testKeyOrderInFeatureCollectionParsing() throws Exception { /* Test parsing of three variations of the same GeoJSON object. */ /* input1 tests parsing when "type" occurs at the top of each sub-object */ String input1 = "{" + " \"type\": \"FeatureCollection\"," + " \"features\": [{" + " \"type\": \"Feature\"," + " \"geometry\": {" + " \"type\": \"GeometryCollection\"," + " \"geometries\": [{" + " \"type\": \"Polygon\"," + " \"coordinates\": [[[100.0, 1.0],[101.0, 1.0],[100.5, 1.5],[100.0, 1.0]]]" + " }]" + " }," + " \"properties\": {}" + " }]" + "}"; /* input2 tests parsing when "type" in a geometry of the geom collection occurs after "coordinates". */ String input2 = "{" + " \"type\": \"FeatureCollection\"," + " \"features\": [{" + " \"type\": \"Feature\"," + " \"geometry\": {" + " \"type\": \"GeometryCollection\"," + " \"geometries\": [{" + " \"coordinates\": [[[100.0, 1.0],[101.0, 1.0],[100.5, 1.5],[100.0, 1.0]]]," + " \"type\": \"Polygon\"" + " }]" + " }," + " \"properties\": {}" + " }]" + "}"; /* input3 is similar to input 2 but also tests parsing when "type" for the feature collection occurs after * "features". */ String input3 = "{" + " \"features\": [{" + " \"type\": \"Feature\"," + " \"geometry\": {" + " \"type\": \"GeometryCollection\"," + " \"geometries\": [{" + " \"coordinates\": [[[100.0, 1.0],[101.0, 1.0],[100.5, 1.5],[100.0, 1.0]]]," + " \"type\": \"Polygon\"" + " }]" + " }," + " \"properties\": {}" + " }]," + " \"type\": \"FeatureCollection\"" + "}"; GeometryFactory factory = new GeometryFactory(); Point expectedLastPoint = factory.createPoint(new Coordinate(100.0, 1.0)); /* test input 1 */ FeatureCollection featureCollection = fjson.readFeatureCollection(input1); testKeyOrderInFeatureCollectionParsing_VerifyContents(featureCollection, expectedLastPoint); /* test input 2 */ featureCollection = fjson.readFeatureCollection(input2); testKeyOrderInFeatureCollectionParsing_VerifyContents(featureCollection, expectedLastPoint); /* test input 3 */ featureCollection = fjson.readFeatureCollection(input3); testKeyOrderInFeatureCollectionParsing_VerifyContents(featureCollection, expectedLastPoint); } /* * Helper function that specifically supports test case testParseFeatureCollectionKeyOrder */ private final void testKeyOrderInFeatureCollectionParsing_VerifyContents(FeatureCollection featureCollection, Point expectedLastPoint) { assertNotNull(featureCollection); assertNotNull(expectedLastPoint); assertEquals(1, featureCollection.size(), 0); FeatureIterator fiter = featureCollection.features(); assertTrue(fiter.hasNext()); Feature feature = fiter.next(); GeometryAttribute geomAttrib = feature.getDefaultGeometryProperty(); Object collectionObj = geomAttrib.getValue(); assertTrue(collectionObj instanceof GeometryCollection); GeometryCollection geomCollection = (GeometryCollection)collectionObj; assertEquals(1, geomCollection.getNumGeometries()); Object geomObj = geomCollection.getGeometryN(0); assertTrue(geomObj instanceof Polygon); Polygon polygon = (Polygon)geomObj; assertEquals(4, polygon.getNumPoints()); assertEquals(1, polygon.getNumGeometries(), 0); LineString outerBoundary = polygon.getExteriorRing(); assertEquals(4, outerBoundary.getNumPoints()); Point lastPoint = outerBoundary.getPointN(3); assertTrue(lastPoint.equalsExact(expectedLastPoint)); assertFalse(fiter.hasNext()); } }