Index: /applications/editors/josm/plugins/pbf/.checkstyle
===================================================================
--- /applications/editors/josm/plugins/pbf/.checkstyle	(revision 32859)
+++ /applications/editors/josm/plugins/pbf/.checkstyle	(revision 32859)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
+  <local-check-config name="JOSM" location="/JOSM/tools/checkstyle/josm_checks.xml" type="project" description="">
+    <additional-data name="protect-config-file" value="false"/>
+  </local-check-config>
+  <fileset name="all" enabled="true" check-config-name="JOSM" local="true">
+    <file-match-pattern match-pattern="." include-pattern="true"/>
+  </fileset>
+  <filter name="DerivedFiles" enabled="true"/>
+  <filter name="FilesFromPackage" enabled="true">
+    <filter-data value="src/com"/>
+    <filter-data value="src/crosby"/>
+    <filter-data value="gen/com"/>
+    <filter-data value="gen/crosby"/>
+    <filter-data value="data"/>
+    <filter-data value="images"/>
+    <filter-data value="styles"/>
+    <filter-data value="resources"/>
+    <filter-data value="scripts"/>
+  </filter>
+</fileset-config>
Index: /applications/editors/josm/plugins/pbf/.classpath
===================================================================
--- /applications/editors/josm/plugins/pbf/.classpath	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/.classpath	(revision 32859)
@@ -3,6 +3,8 @@
 	<classpathentry kind="src" path="gen"/>
 	<classpathentry excluding="crosby/binary/test/" kind="src" path="src"/>
+	<classpathentry kind="src" path="test/unit"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/JOSM"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
 	<classpathentry kind="output" path="build"/>
 </classpath>
Index: /applications/editors/josm/plugins/pbf/.project
===================================================================
--- /applications/editors/josm/plugins/pbf/.project	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/.project	(revision 32859)
@@ -16,8 +16,14 @@
 			</arguments>
 		</buildCommand>
+		<buildCommand>
+			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
 	</buildSpec>
 	<natures>
 		<nature>org.sonar.ide.eclipse.core.sonarNature</nature>
 		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
 	</natures>
 </projectDescription>
Index: /applications/editors/josm/plugins/pbf/.settings/org.eclipse.jdt.ui.prefs
===================================================================
--- /applications/editors/josm/plugins/pbf/.settings/org.eclipse.jdt.ui.prefs	(revision 32859)
+++ /applications/editors/josm/plugins/pbf/.settings/org.eclipse.jdt.ui.prefs	(revision 32859)
@@ -0,0 +1,60 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
Index: /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/PbfConstants.java
===================================================================
--- /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/PbfConstants.java	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/PbfConstants.java	(revision 32859)
@@ -7,18 +7,18 @@
 
 /**
- * 
+ * PBF constants.
  * @author Don-vip
- *
  */
 public interface PbfConstants {
-    
+
     /**
      * File extension.
      */
-    public static final String EXTENSION = "osm.pbf";
-    
+    String EXTENSION = "osm.pbf";
+
     /**
      * File filter used in import/export dialogs.
      */
-    public static final ExtensionFileFilter FILE_FILTER = new ExtensionFileFilter(EXTENSION, EXTENSION, tr("OSM Server Files pbf compressed") + " (*."+EXTENSION+")");
+    ExtensionFileFilter FILE_FILTER = new ExtensionFileFilter(EXTENSION, EXTENSION,
+            tr("OSM Server Files pbf compressed") + " (*."+EXTENSION+")");
 }
Index: /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/action/DownloadPbfTask.java
===================================================================
--- /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/action/DownloadPbfTask.java	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/action/DownloadPbfTask.java	(revision 32859)
@@ -13,21 +13,21 @@
 import org.openstreetmap.josm.plugins.pbf.io.PbfServerReader;
 
+/**
+ * Task allowing to download remote PBF files.
+ */
 public class DownloadPbfTask extends DownloadOsmTask implements PbfConstants {
 
-	@Override
-	public Future<?> download(boolean newLayer, Bounds downloadArea,
-			ProgressMonitor progressMonitor) {
-		return null;
-	}
+    @Override
+    public Future<?> download(boolean newLayer, Bounds downloadArea, ProgressMonitor progressMonitor) {
+        return null;
+    }
 
-	@Override
-	public Future<?> loadUrl(boolean newLayer, String url,
-			ProgressMonitor progressMonitor) {
-        downloadTask = new DownloadTask(newLayer,
-                new PbfServerReader(url), progressMonitor);
+    @Override
+    public Future<?> loadUrl(boolean newLayer, String url, ProgressMonitor progressMonitor) {
+        downloadTask = new DownloadTask(newLayer, new PbfServerReader(url), progressMonitor);
         // We need submit instead of execute so we can wait for it to finish and get the error
         // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
         return Main.worker.submit(downloadTask);
-	}
+    }
 
     @Override
Index: /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfExporter.java
===================================================================
--- /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfExporter.java	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfExporter.java	(revision 32859)
@@ -3,5 +3,4 @@
 
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -13,9 +12,12 @@
 
 /**
+ * Exports data to a .pbf file.
  * @author Don-vip
- *
  */
 public class PbfExporter extends OsmExporter {
 
+    /**
+     * Constructs a new {@code PbfExporter}.
+     */
     public PbfExporter() {
         super(PbfConstants.FILE_FILTER);
@@ -23,5 +25,5 @@
 
     @Override
-    protected void doSave(File file, OsmDataLayer layer) throws IOException, FileNotFoundException {
+    protected void doSave(File file, OsmDataLayer layer) throws IOException {
         try (
             OutputStream out = new FileOutputStream(file);
Index: /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfImporter.java
===================================================================
--- /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfImporter.java	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfImporter.java	(revision 32859)
@@ -8,27 +8,31 @@
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.io.IllegalDataException;
-import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.io.OsmImporter;
 import org.openstreetmap.josm.plugins.pbf.PbfConstants;
-import org.xml.sax.SAXException;
 
 /**
+ * Imports data from a .pbf file.
  * @author Don-vip
- *
  */
 public class PbfImporter extends OsmImporter {
 
+    /**
+     * Constructs a new {@code PbfImporter}.
+     */
     public PbfImporter() {
         super(PbfConstants.FILE_FILTER);
     }
 
-	@Override
-	protected DataSet parseDataSet(InputStream in, ProgressMonitor progressMonitor) throws IllegalDataException {
-		return PbfReader.parseDataSet(in, progressMonitor);
-	}
+    @Override
+    protected DataSet parseDataSet(InputStream in, ProgressMonitor progressMonitor) throws IllegalDataException {
+        return PbfReader.parseDataSet(in, progressMonitor);
+    }
 
-	protected DataSet parseDataSet(final String source) throws IOException, SAXException, IllegalDataException {
-        return parseDataSet(new CachedFile(source).getInputStream(), NullProgressMonitor.INSTANCE);
-	}
+    protected DataSet parseDataSet(final String source) throws IOException, IllegalDataException {
+        try (CachedFile cf = new CachedFile(source)) {
+            return parseDataSet(cf.getInputStream(), NullProgressMonitor.INSTANCE);
+        }
+    }
 }
Index: /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfReader.java
===================================================================
--- /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfReader.java	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfReader.java	(revision 32859)
@@ -19,4 +19,5 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.Relation;
@@ -32,28 +33,30 @@
 import crosby.binary.BinaryParser;
 import crosby.binary.Osmformat;
+import crosby.binary.Osmformat.DenseInfo;
 import crosby.binary.Osmformat.DenseNodes;
 import crosby.binary.Osmformat.HeaderBBox;
 import crosby.binary.Osmformat.HeaderBlock;
 import crosby.binary.Osmformat.Info;
+import crosby.binary.Osmformat.Relation.MemberType;
 import crosby.binary.file.BlockInputStream;
 import crosby.binary.file.FileBlockPosition;
 
 /**
+ * OSM reader for the PBF file format.
  * @author Don-vip
- *
  */
 public class PbfReader extends AbstractReader {
-    
+
     protected class PbfParser extends BinaryParser {
 
-        public IllegalDataException exception = null;
-        
+        private IllegalDataException exception = null;
+        private boolean discourageUpload;
         private double parseRawDegrees(long raw) {
             return raw * .000000001;
         }
-        
+
         @Override
         protected void parse(HeaderBlock header) {
-            
+
             for (String requiredFeature : header.getRequiredFeaturesList()) {
                 switch (requiredFeature) {
@@ -67,5 +70,5 @@
                 }
             }
-            
+
             HeaderBBox bbox = header.getBbox();
             if (bbox != null) {
@@ -75,6 +78,5 @@
                 double maxlon = parseRawDegrees(bbox.getRight());
                 Bounds b = new Bounds(minlat, minlon, maxlat, maxlon);
-                if (!b.isCollapsed() && LatLon.isValidLat(minlat) && LatLon.isValidLat(maxlat) 
-                                     && LatLon.isValidLon(minlon) && LatLon.isValidLon(maxlon)) {
+                if (!b.isCollapsed() && areCoordinatesValid(minlat, minlon, maxlat, maxlon)) {
                     ds.dataSources.add(new DataSource(b, header.getSource()));
                 } else {
@@ -84,9 +86,28 @@
         }
 
+        private boolean areCoordinatesValid(double minlat, double minlon, double maxlat, double maxlon) {
+            return LatLon.isValidLat(minlat) && LatLon.isValidLat(maxlat)
+                && LatLon.isValidLon(minlon) && LatLon.isValidLon(maxlon);
+        }
+
+        private void setMetadata(OsmPrimitive osm, Info info) throws IllegalDataException {
+            if (info.hasChangeset()) {
+                checkChangesetId(info.getChangeset());
+                osm.setChangesetId((int) info.getChangeset());
+            }
+            if (info.hasUid() && info.hasUserSid()) {
+                osm.setUser(User.createOsmUser(info.getUid(), getStringById(info.getUserSid())));
+            }
+            if (info.hasTimestamp()) {
+                checkTimestamp(info.getTimestamp());
+                osm.setTimestamp(getDate(info));
+            }
+        }
+
         @Override
         public boolean skipBlock(FileBlockPosition block) {
             return exception != null;
         }
-        
+
         protected void checkCoordinates(LatLon coor) throws IllegalDataException {
             if (!coor.isValid()) {
@@ -100,5 +121,5 @@
             }
         }
-        
+
         protected void checkTimestamp(long timestamp) throws IllegalDataException {
             if (timestamp < 0) {
@@ -109,4 +130,6 @@
         @Override
         protected void parseDense(DenseNodes nodes) {
+            if (!nodes.hasDenseinfo())
+                discourageUpload = true;
             if (exception == null) {
                 try {
@@ -122,16 +145,27 @@
                     for (int i = 0; i < nodes.getIdCount(); i++) {
                         // Id (delta) and version (normal)
-                        Node node = new Node(nodeId+=nodes.getId(i), nodes.getDenseinfo().getVersion(i));
+                        Node node = new Node(nodeId += nodes.getId(i), nodes.hasDenseinfo() ? nodes.getDenseinfo().getVersion(i) : 1);
                         // Lat/Lon (delta)
-                        node.setCoor(new LatLon(parseLat(nodeLat+=nodes.getLat(i)), parseLon(nodeLon+=nodes.getLon(i))).getRoundedToOsmPrecision());
+                        node.setCoor(new LatLon(parseLat(nodeLat += nodes.getLat(i)),
+                                                parseLon(nodeLon += nodes.getLon(i))).getRoundedToOsmPrecision());
                         checkCoordinates(node.getCoor());
-                        // Changeset (delta)
-                        checkChangesetId(changesetId+=nodes.getDenseinfo().getChangeset(i));
-                        node.setChangesetId((int) changesetId);
-                        // User (delta)
-                        node.setUser(User.createOsmUser(uid+=nodes.getDenseinfo().getUid(i), getStringById(suid+=nodes.getDenseinfo().getUserSid(i))));
-                        // Timestamp (delta)
-                        checkTimestamp(timestamp+=nodes.getDenseinfo().getTimestamp(i));
-                        node.setTimestamp(new Date(date_granularity * timestamp));
+                        if (nodes.hasDenseinfo()) {
+                            DenseInfo info = nodes.getDenseinfo();
+                            // Changeset (delta)
+                            if (info.getChangesetCount() > i) {
+                                checkChangesetId(changesetId += info.getChangeset(i));
+                                node.setChangesetId((int) changesetId);
+                            }
+                            // User (delta)
+                            if (info.getUidCount() > i && info.getUserSidCount() > i) {
+                                node.setUser(User.createOsmUser(uid += info.getUid(i),
+                                                 getStringById(suid += info.getUserSid(i))));
+                            }
+                            // Timestamp (delta)
+                            if (info.getTimestampCount() > i) {
+                                checkTimestamp(timestamp += info.getTimestamp(i));
+                                node.setTimestamp(new Date(date_granularity * timestamp));
+                            }
+                        }
                         // A single table contains all keys/values of all nodes.
                         // Each node's tags are encoded in alternating <key_id> <value_id>.
@@ -139,10 +173,9 @@
                         Map<String, String> keys = new HashMap<>();
                         while (keyIndex < nodes.getKeysValsCount()) {
-                            int key_id = nodes.getKeysVals(keyIndex++);
-                            if (key_id == 0) {
+                            int keyId = nodes.getKeysVals(keyIndex++);
+                            if (keyId == 0) {
                                 break; // End of current node's tags
                             } else if (keyIndex < nodes.getKeysValsCount()) {
-                                int value_id = nodes.getKeysVals(keyIndex++);
-                                keys.put(getStringById(key_id), getStringById(value_id));
+                                keys.put(getStringById(keyId), getStringById(nodes.getKeysVals(keyIndex++)));
                             } else {
                                 throw new IllegalDataException(tr("Invalid DenseNodes key/values table"));
@@ -163,15 +196,13 @@
                 try {
                     for (Osmformat.Node n : osmNodes) {
-                    	final Info info = n.getInfo();
-                        final Node node = new Node(n.getId(), info.getVersion());
+                        final Info info = n.getInfo();
+                        if (!info.hasVersion())
+                            discourageUpload = true;
+                        final Node node = new Node(n.getId(), info.hasVersion() ? info.getVersion() : 1);
                         node.setCoor(new LatLon(parseLat(n.getLat()), parseLon(n.getLon())).getRoundedToOsmPrecision());
                         checkCoordinates(node.getCoor());
-                        checkChangesetId(info.getChangeset());
-                        node.setChangesetId((int) info.getChangeset());
-                        node.setUser(User.createOsmUser(info.getUid(), getStringById(info.getUserSid())));
-                        checkTimestamp(info.getTimestamp());
-                        node.setTimestamp(getDate(info));
+                        setMetadata(node, info);
                         Map<String, String> keys = new HashMap<>();
-                        for (int i=0; i<n.getKeysCount(); i++) {
+                        for (int i = 0; i < n.getKeysCount(); i++) {
                             keys.put(getStringById(n.getKeys(i)), getStringById(n.getVals(i)));
                         }
@@ -184,5 +215,5 @@
             }
         }
-        
+
         @Override
         protected void parseWays(List<Osmformat.Way> osmWays) {
@@ -190,13 +221,11 @@
                 try {
                     for (Osmformat.Way w : osmWays) {
-                    	final Info info = w.getInfo();
-                        final Way way = new Way(w.getId(), info.getVersion());
-                        checkChangesetId(info.getChangeset());
-                        way.setChangesetId((int) info.getChangeset());
-                        way.setUser(User.createOsmUser(info.getUid(), getStringById(info.getUserSid())));
-                        checkTimestamp(info.getTimestamp());
-                        way.setTimestamp(getDate(info));
+                        final Info info = w.getInfo();
+                        if (!info.hasVersion())
+                            discourageUpload = true;
+                        final Way way = new Way(w.getId(), info.hasVersion() ? info.getVersion() : 1);
+                        setMetadata(way, info);
                         Map<String, String> keys = new HashMap<>();
-                        for (int i=0; i<w.getKeysCount(); i++) {
+                        for (int i = 0; i < w.getKeysCount(); i++) {
                             keys.put(getStringById(w.getKeys(i)), getStringById(w.getVals(i)));
                         }
@@ -205,5 +234,5 @@
                         Collection<Long> nodeIds = new ArrayList<>();
                         for (Long id : w.getRefsList()) {
-                            nodeIds.add(previousId+=id);
+                            nodeIds.add(previousId += id);
                         }
                         ways.put(way.getUniqueId(), nodeIds);
@@ -215,5 +244,5 @@
             }
         }
-        
+
         @Override
         protected void parseRelations(List<Osmformat.Relation> osmRels) {
@@ -221,13 +250,11 @@
                 try {
                     for (Osmformat.Relation r : osmRels) {
-                    	final Info info = r.getInfo();
-                        final Relation rel = new Relation(r.getId(), info.getVersion());
-                        checkChangesetId(info.getChangeset());
-                        rel.setChangesetId((int) info.getChangeset());
-                        rel.setUser(User.createOsmUser(info.getUid(), getStringById(info.getUserSid())));
-                        checkTimestamp(info.getTimestamp());
-                        rel.setTimestamp(getDate(info));
+                        final Info info = r.getInfo();
+                        if (!info.hasVersion())
+                            discourageUpload = true;
+                        final Relation rel = new Relation(r.getId(), info.hasVersion() ? info.getVersion() : 1);
+                        setMetadata(rel, info);
                         Map<String, String> keys = new HashMap<>();
-                        for (int i=0; i<r.getKeysCount(); i++) {
+                        for (int i = 0; i < r.getKeysCount(); i++) {
                             keys.put(getStringById(r.getKeys(i)), getStringById(r.getVals(i)));
                         }
@@ -235,20 +262,9 @@
                         long previousId = 0; // Member ids are delta coded
                         Collection<RelationMemberData> members = new ArrayList<>();
-                        for (int i = 0; i<r.getMemidsCount(); i++) {
-                            long id = previousId+=r.getMemids(i);
-                            String role = getStringById(r.getRolesSid(i));
-                            OsmPrimitiveType type = null;
-                            switch (r.getTypes(i)) {
-                                case NODE:
-                                    type = OsmPrimitiveType.NODE;
-                                    break;
-                                case WAY:
-                                    type = OsmPrimitiveType.WAY;
-                                    break;
-                                case RELATION:
-                                    type = OsmPrimitiveType.RELATION;
-                                    break;
-                            }
-                            members.add(new RelationMemberData(role, type, id));
+                        for (int i = 0; i < r.getMemidsCount(); i++) {
+                            members.add(new RelationMemberData(
+                                    getStringById(r.getRolesSid(i)),
+                                    mapOsmType(r.getTypes(i)),
+                                    previousId += r.getMemids(i)));
                         }
                         relations.put(rel.getUniqueId(), members);
@@ -259,13 +275,30 @@
                 }
             }
+            if (discourageUpload)
+                ds.setUploadDiscouraged(true);
+        }
+
+        private OsmPrimitiveType mapOsmType(MemberType type) {
+            switch (type) {
+            case NODE:
+                return OsmPrimitiveType.NODE;
+            case WAY:
+                return OsmPrimitiveType.WAY;
+            case RELATION:
+                return OsmPrimitiveType.RELATION;
+            default:
+                return null;
+            }
         }
 
         @Override
         public void complete() {
+            if (discourageUpload)
+                ds.setUploadDiscouraged(true);
         }
     }
 
     private PbfParser parser = new PbfParser();
-    
+
     /**
      * Parse the given input source and return the dataset.
@@ -279,21 +312,19 @@
      */
     public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
-        if (progressMonitor == null) {
-            progressMonitor = NullProgressMonitor.INSTANCE;
-        }
+        ProgressMonitor monitor = progressMonitor == null ? NullProgressMonitor.INSTANCE : progressMonitor;
         CheckParameterUtil.ensureParameterNotNull(source, "source");
 
         PbfReader reader = new PbfReader();
-        
+
         try {
-            progressMonitor.beginTask(tr("Prepare OSM data...", 2));
-            progressMonitor.indeterminateSubTask(tr("Reading OSM data..."));
+            monitor.beginTask(tr("Prepare OSM data...", 2));
+            monitor.indeterminateSubTask(tr("Reading OSM data..."));
 
             reader.parse(source);
-            progressMonitor.worked(1);
-
-            progressMonitor.indeterminateSubTask(tr("Preparing data set..."));
+            monitor.worked(1);
+
+            monitor.indeterminateSubTask(tr("Preparing data set..."));
             reader.prepareDataSet();
-            progressMonitor.worked(1);
+            monitor.worked(1);
             return reader.getDataSet();
         } catch (IllegalDataException e) {
@@ -302,5 +333,5 @@
             throw new IllegalDataException(e);
         } finally {
-            progressMonitor.finishTask();
+            monitor.finishTask();
         }
     }
Index: /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfServerReader.java
===================================================================
--- /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfServerReader.java	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfServerReader.java	(revision 32859)
@@ -9,15 +9,22 @@
 import org.openstreetmap.josm.io.OsmTransferException;
 
+/**
+ * This DataReader reads PBF directly from an URL.
+ */
 public class PbfServerReader extends OsmServerReader {
 
-	private String url;
-	
-	public PbfServerReader(String url) {
-		this.url = url;
-	}
+    private String url;
 
-	@Override
-	public DataSet parseOsm(ProgressMonitor progressMonitor)
-			throws OsmTransferException {
+    /**
+     * Constructs a new {@code PbfServerReader}.
+     * @param url source URL
+     */
+    public PbfServerReader(String url) {
+        this.url = url;
+    }
+
+    @Override
+    public DataSet parseOsm(ProgressMonitor progressMonitor)
+            throws OsmTransferException {
         try {
             progressMonitor.beginTask(tr("Contacting Server...", 10));
@@ -28,4 +35,4 @@
             progressMonitor.finishTask();
         }
-	}
+    }
 }
Index: /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfWriter.java
===================================================================
--- /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfWriter.java	(revision 32858)
+++ /applications/editors/josm/plugins/pbf/src/org/openstreetmap/josm/plugins/pbf/io/PbfWriter.java	(revision 32859)
@@ -29,8 +29,16 @@
 import crosby.binary.file.FileBlock;
 
+/**
+ * OSM writer for the PBF file format.
+ * @author Don-vip
+ */
 public class PbfWriter implements Closeable {
 
     private final PbfSerializer out;
 
+    /**
+     * Constructs a new {@code PbfWriter}.
+     * @param out output stream
+     */
     public PbfWriter(OutputStream out) {
         this.out = new PbfSerializer(new BlockOutputStream(out));
@@ -42,5 +50,5 @@
         /** Additional configuration flag for whether to serialize into DenseNodes/DenseInfo? */
         protected boolean useDense = true;
-        
+
         /** Has the header been written yet? */
         protected boolean headerWritten = false;
@@ -48,5 +56,5 @@
         /**
          * Constructs a new {@code PbfSerializer}.
-         * 
+         *
          * @param output The PBF block stream to send serialized data
          */
@@ -57,5 +65,5 @@
         /**
          * Change the flag of whether to use the dense format.
-         * 
+         *
          * @param useDense The new use dense value.
          */
@@ -73,5 +81,5 @@
             /**
              * Add to the queue.
-             * 
+             *
              * @param item The entity to add
              */
@@ -101,10 +109,12 @@
                 }
 
-                long lasttimestamp = 0, lastchangeset = 0;
-                int lastuserSid = 0, lastuid = 0;
+                long lasttimestamp = 0;
+                long lastchangeset = 0;
+                int lastuserSid = 0;
+                int lastuid = 0;
                 StringTable stable = getStringTable();
                 for (OsmPrimitive e : entities) {
 
-                    int uid =  e.getUser() == null ? -1 : (int) e.getUser().getId();
+                    int uid = e.getUser() == null ? -1 : (int) e.getUser().getId();
                     int userSid = stable.getIndex(e.getUser() == null ? "" : e.getUser().getName());
                     int timestamp = (int) (e.getTimestamp().getTime() / date_granularity);
@@ -139,7 +149,8 @@
             }
         }
-        
+
         private class NodeGroup extends Prim<Node> implements PrimGroupWriterInterface {
 
+            @Override
             public Osmformat.PrimitiveGroup serialize() {
                 if (useDense) {
@@ -154,5 +165,5 @@
              */
             public Osmformat.PrimitiveGroup serializeDense() {
-                if (contents.size() == 0) {
+                if (contents.isEmpty()) {
                     return null;
                 }
@@ -160,5 +171,7 @@
                 StringTable stable = getStringTable();
 
-                long lastlat = 0, lastlon = 0, lastid = 0;
+                long lastlat = 0;
+                long lastlon = 0;
+                long lastid = 0;
                 Osmformat.DenseNodes.Builder bi = Osmformat.DenseNodes.newBuilder();
                 boolean doesBlockHaveTags = false;
@@ -202,9 +215,9 @@
             /**
              * Serialize all nodes in the non-dense format.
-             * 
+             *
              * @param parentbuilder Add to this PrimitiveBlock.
              */
             public Osmformat.PrimitiveGroup serializeNonDense() {
-                if (contents.size() == 0) {
+                if (contents.isEmpty()) {
                     return null;
                 }
@@ -235,6 +248,7 @@
         private class WayGroup extends Prim<Way> implements
                 PrimGroupWriterInterface {
+            @Override
             public Osmformat.PrimitiveGroup serialize() {
-                if (contents.size() == 0) {
+                if (contents.isEmpty()) {
                     return null;
                 }
@@ -265,4 +279,5 @@
 
         private class RelationGroup extends Prim<Relation> implements PrimGroupWriterInterface {
+            @Override
             public void addStringsToStringtable() {
                 StringTable stable = getStringTable();
@@ -275,6 +290,7 @@
             }
 
+            @Override
             public Osmformat.PrimitiveGroup serialize() {
-                if (contents.size() == 0) {
+                if (contents.isEmpty()) {
                     return null;
                 }
@@ -299,5 +315,5 @@
                             bi.addTypes(MemberType.RELATION);
                         } else {
-                            assert (false); // Software bug: Unknown entity.
+                            assert false; // Software bug: Unknown entity.
                         }
                         bi.addRolesSid(stable.getIndex(j.getRole()));
@@ -321,5 +337,5 @@
         private NodeGroup nodes;
         private RelationGroup relations;
-        
+
         private Processor processor = new Processor();
 
@@ -350,4 +366,8 @@
             }
 
+            /**
+             * Process node.
+             * @param node node
+             */
             public void processNode(Node node) {
                 if (nodes == null) {
@@ -362,4 +382,8 @@
             }
 
+            /**
+             * Process way.
+             * @param way way
+             */
             public void processWay(Way way) {
                 if (ways == null) {
@@ -372,4 +396,8 @@
             }
 
+            /**
+             * Process relation.
+             * @param relation relation
+             */
             public void processRelation(Relation relation) {
                 if (relations == null) {
@@ -404,5 +432,5 @@
         public void processBounds(DataSource entity) {
             Osmformat.HeaderBlock.Builder headerblock = Osmformat.HeaderBlock.newBuilder();
-            
+
             Osmformat.HeaderBBox.Builder bbox = Osmformat.HeaderBBox.newBuilder();
             bbox.setLeft(mapRawDegrees(entity.bounds.getMinLon()));
@@ -429,5 +457,5 @@
         /**
          * Write the header fields that are always needed.
-         * 
+         *
          * @param headerblock Incomplete builder to complete and write.
          * */
@@ -446,5 +474,5 @@
             headerWritten = true;
         }
-        
+
         public void process(DataSet ds) {
             processor.processSources(ds.dataSources);
@@ -471,8 +499,16 @@
     }
 
+    /**
+     * Writes data to an OSM data layer.
+     * @param layer data layer
+     */
     public void writeLayer(OsmDataLayer layer) {
         writeData(layer.data);
     }
 
+    /**
+     * Writes data to a dataset.
+     * @param ds dataset
+     */
     public void writeData(DataSet ds) {
         out.process(ds);
Index: /applications/editors/josm/plugins/pbf/test/unit/org/openstreetmap/josm/plugins/pbf/io/PbfImporterTest.java
===================================================================
--- /applications/editors/josm/plugins/pbf/test/unit/org/openstreetmap/josm/plugins/pbf/io/PbfImporterTest.java	(revision 32859)
+++ /applications/editors/josm/plugins/pbf/test/unit/org/openstreetmap/josm/plugins/pbf/io/PbfImporterTest.java	(revision 32859)
@@ -0,0 +1,69 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.pbf.io;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.User;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+/**
+ * Unit tests for {@link PbfImporter}.
+ */
+public class PbfImporterTest {
+
+    /**
+     * Setup test.
+     */
+    @Rule
+    public JOSMTestRules rules = new JOSMTestRules().preferences();
+
+    private static void checkUserNull(OsmPrimitive osm, boolean hasToBeNull) {
+        User usr = osm.getUser();
+        if (hasToBeNull) {
+            assertNull(osm + " -> " + usr, usr);
+        } else {
+            assertNotNull(osm + " -> " + usr, usr);
+        }
+    }
+
+    private static void doTestMonaco(String file, boolean hasMetadataToBeNull) throws IOException, IllegalDataException {
+        DataSet ds = new PbfImporter().parseDataSet(file);
+        assertNotNull(ds);
+        assertEquals(18685, ds.getNodes().size());
+        assertEquals(16735, ds.getWays().size());
+        assertEquals(476, ds.getRelations().size());
+
+        checkUserNull(ds.getPrimitiveById(1790048269, OsmPrimitiveType.NODE), hasMetadataToBeNull);
+        checkUserNull(ds.getPrimitiveById(4227155, OsmPrimitiveType.WAY), hasMetadataToBeNull);
+        checkUserNull(ds.getPrimitiveById(393226, OsmPrimitiveType.RELATION), hasMetadataToBeNull);
+    }
+
+    /**
+     * Unit test of {@link PbfImporter#parseDataSet(String)}.
+     * @throws Exception if an error occurs
+     */
+    @Test
+    public void testParseDataSet() throws Exception {
+        doTestMonaco(TestUtils.getTestDataRoot() + "/monaco-latest.osm.pbf", false);
+    }
+
+    /**
+     * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/10132">Ticket #10132</a>.
+     * @throws Exception if an error occurs
+     */
+    @Test
+    public void testTicket10132() throws Exception {
+        doTestMonaco(TestUtils.getRegressionDataFile(10132, "Monaco-SP.osm.pbf"), true);
+    }
+}
