Index: trunk/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java	(revision 10816)
+++ trunk/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java	(revision 10817)
@@ -14,10 +14,13 @@
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.ForkJoinTask;
 import java.util.concurrent.RecursiveTask;
+import java.util.stream.Collectors;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Geometry;
 import org.openstreetmap.josm.tools.Geometry.PolygonIntersection;
@@ -165,4 +168,21 @@
 
     /**
+     * Joins the given {@code multipolygon} to a pair of outer and inner multipolygon rings.
+     *
+     * @param multipolygon the multipolygon to join.
+     * @return a pair of outer and inner multipolygon rings.
+     * @throws JoinedPolygonCreationException if the creation fails.
+     */
+    public static Pair<List<JoinedPolygon>, List<JoinedPolygon>> joinWays(Relation multipolygon) throws JoinedPolygonCreationException {
+        CheckParameterUtil.ensureThat(multipolygon.isMultipolygon(), "multipolygon.isMultipolygon");
+        final Map<String, Set<Way>> members = multipolygon.getMembers().stream()
+                .filter(RelationMember::isWay)
+                .collect(Collectors.groupingBy(RelationMember::getRole, Collectors.mapping(RelationMember::getWay, Collectors.toSet())));
+        final List<JoinedPolygon> outerRings = joinWays(members.getOrDefault("outer", Collections.emptySet()));
+        final List<JoinedPolygon> innerRings = joinWays(members.getOrDefault("inner", Collections.emptySet()));
+        return Pair.create(outerRings, innerRings);
+    }
+
+    /**
      * Joins the given {@code ways} to multipolygon rings.
      * @param ways the ways to join.
Index: trunk/src/org/openstreetmap/josm/io/GeoJSONWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GeoJSONWriter.java	(revision 10816)
+++ trunk/src/org/openstreetmap/josm/io/GeoJSONWriter.java	(revision 10817)
@@ -7,6 +7,8 @@
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.stream.Stream;
 
 import javax.json.Json;
@@ -20,13 +22,15 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.INode;
-import org.openstreetmap.josm.data.osm.IRelation;
-import org.openstreetmap.josm.data.osm.IWay;
+import org.openstreetmap.josm.data.osm.MultipolygonBuilder;
+import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
+import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.mappaint.ElemStyles;
+import org.openstreetmap.josm.tools.Pair;
 
 /**
@@ -80,5 +84,5 @@
     }
 
-    private class GeometryPrimitiveVisitor implements PrimitiveVisitor {
+    private class GeometryPrimitiveVisitor extends AbstractVisitor {
 
         private final JsonObjectBuilder geomObj;
@@ -89,30 +93,41 @@
 
         @Override
-        public void visit(INode n) {
+        public void visit(Node n) {
             geomObj.add("type", "Point");
             LatLon ll = n.getCoor();
             if (ll != null) {
-                geomObj.add("coordinates", getCoorArray(Json.createArrayBuilder(), n.getCoor()));
+                geomObj.add("coordinates", getCoorArray(null, n.getCoor()));
             }
         }
 
         @Override
-        public void visit(IWay w) {
-            geomObj.add("type", "LineString");
-            if (w instanceof Way) {
-                JsonArrayBuilder array = Json.createArrayBuilder();
-                for (Node n : ((Way) w).getNodes()) {
-                    LatLon ll = n.getCoor();
-                    if (ll != null) {
-                        array.add(getCoorArray(Json.createArrayBuilder(), ll));
-                    }
+        public void visit(Way w) {
+            if (w != null) {
+                final JsonArrayBuilder array = getCoorsArray(w.getNodes());
+                if (ElemStyles.hasAreaElemStyle(w, false)) {
+                    final JsonArrayBuilder container = Json.createArrayBuilder().add(array);
+                    geomObj.add("type", "Polygon");
+                    geomObj.add("coordinates", container);
+                } else {
+                    geomObj.add("type", "LineString");
+                    geomObj.add("coordinates", array);
                 }
-                geomObj.add("coordinates", array);
             }
         }
 
         @Override
-        public void visit(IRelation r) {
-            // Do nothing
+        public void visit(Relation r) {
+            if (r != null && r.isMultipolygon() && !r.hasIncompleteMembers()) {
+                final Pair<List<JoinedPolygon>, List<JoinedPolygon>> mp = MultipolygonBuilder.joinWays(r);
+                final JsonArrayBuilder polygon = Json.createArrayBuilder();
+                Stream.concat(mp.a.stream(), mp.b.stream())
+                        .map(p -> getCoorsArray(p.getNodes())
+                                // since first node is not duplicated as last node
+                                .add(getCoorArray(null, p.getNodes().get(0).getCoor())))
+                        .forEach(polygon::add);
+                geomObj.add("type", "MultiPolygon");
+                final JsonArrayBuilder multiPolygon = Json.createArrayBuilder().add(polygon);
+                geomObj.add("coordinates", multiPolygon);
+            }
         }
     }
@@ -123,7 +138,18 @@
 
     private static JsonArrayBuilder getCoorArray(JsonArrayBuilder builder, EastNorth c) {
-        return builder
+        return builder != null ? builder : Json.createArrayBuilder()
                 .add(BigDecimal.valueOf(c.getX()).setScale(11, RoundingMode.HALF_UP))
                 .add(BigDecimal.valueOf(c.getY()).setScale(11, RoundingMode.HALF_UP));
+    }
+
+    private JsonArrayBuilder getCoorsArray(Iterable<Node> nodes) {
+        final JsonArrayBuilder builder = Json.createArrayBuilder();
+        for (Node n : nodes) {
+            LatLon ll = n.getCoor();
+            if (ll != null) {
+                builder.add(getCoorArray(null, ll));
+            }
+        }
+        return builder;
     }
 
@@ -177,10 +203,5 @@
         JsonArrayBuilder array = Json.createArrayBuilder();
         if (ds != null) {
-            for (Node n : ds.getNodes()) {
-                appendPrimitive(n, array);
-            }
-            for (Way w : ds.getWays()) {
-                appendPrimitive(w, array);
-            }
+            ds.allPrimitives().forEach(p -> appendPrimitive(p, array));
         }
         object.add("features", array);
Index: trunk/src/org/openstreetmap/josm/tools/Geometry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 10816)
+++ trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 10817)
@@ -12,5 +12,4 @@
 import java.util.Comparator;
 import java.util.EnumSet;
-import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -26,10 +25,9 @@
 import org.openstreetmap.josm.data.osm.BBox;
 import org.openstreetmap.josm.data.osm.MultipolygonBuilder;
+import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.NodePositionComparator;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
@@ -863,21 +861,4 @@
     }
 
-    public static class MultiPolygonMembers {
-        public final Set<Way> outers = new HashSet<>();
-        public final Set<Way> inners = new HashSet<>();
-
-        public MultiPolygonMembers(Relation multiPolygon) {
-            for (RelationMember m : multiPolygon.getMembers()) {
-                if (m.getType().equals(OsmPrimitiveType.WAY)) {
-                    if ("outer".equals(m.getRole())) {
-                        outers.add(m.getWay());
-                    } else if ("inner".equals(m.getRole())) {
-                        inners.add(m.getWay());
-                    }
-                }
-            }
-        }
-    }
-
     /**
      * Tests if the {@code node} is inside the multipolygon {@code multiPolygon}. The nullable argument
@@ -904,11 +885,7 @@
     public static boolean isPolygonInsideMultiPolygon(List<Node> nodes, Relation multiPolygon, Predicate<Way> isOuterWayAMatch) {
         // Extract outer/inner members from multipolygon
-        final MultiPolygonMembers mpm = new MultiPolygonMembers(multiPolygon);
-        // Construct complete rings for the inner/outer members
-        final List<MultipolygonBuilder.JoinedPolygon> outerRings;
-        final List<MultipolygonBuilder.JoinedPolygon> innerRings;
+        final Pair<List<JoinedPolygon>, List<JoinedPolygon>> outerInner;
         try {
-            outerRings = MultipolygonBuilder.joinWays(mpm.outers);
-            innerRings = MultipolygonBuilder.joinWays(mpm.inners);
+            outerInner = MultipolygonBuilder.joinWays(multiPolygon);
         } catch (MultipolygonBuilder.JoinedPolygonCreationException ex) {
             Main.trace(ex);
@@ -917,5 +894,5 @@
         }
         // Test if object is inside an outer member
-        for (MultipolygonBuilder.JoinedPolygon out : outerRings) {
+        for (JoinedPolygon out : outerInner.a) {
             if (nodes.size() == 1
                     ? nodeInsidePolygon(nodes.get(0), out.getNodes())
@@ -924,5 +901,5 @@
                 boolean insideInner = false;
                 // If inside an outer, check it is not inside an inner
-                for (MultipolygonBuilder.JoinedPolygon in : innerRings) {
+                for (JoinedPolygon in : outerInner.b) {
                     if (polygonIntersection(in.getNodes(), out.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND
                             && (nodes.size() == 1
Index: trunk/test/unit/org/openstreetmap/josm/io/GeoJSONWriterTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/io/GeoJSONWriterTest.java	(revision 10816)
+++ trunk/test/unit/org/openstreetmap/josm/io/GeoJSONWriterTest.java	(revision 10817)
@@ -3,8 +3,10 @@
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.openstreetmap.josm.JOSMFixture;
+import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -12,4 +14,6 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
+
+import java.io.FileInputStream;
 
 /**
@@ -66,3 +70,16 @@
                 "}").replace("'", "\""), writer.write().trim());
     }
+
+    /**
+     * Unit test for multipolygon
+     */
+    @Test
+    public void testMultipolygon() throws Exception {
+        try (FileInputStream in = new FileInputStream(TestUtils.getTestDataRoot() + "multipolygon.osm")) {
+            DataSet ds = OsmReader.parseDataSet(in, null);
+            final OsmDataLayer layer = new OsmDataLayer(ds, "foo", null);
+            final GeoJSONWriter writer = new GeoJSONWriter(layer, ProjectionPreference.wgs84.getProjection());
+            assertTrue(writer.write().contains("MultiPolygon"));
+        }
+    }
 }
