Bug 1244944 - Don't catch or throw ParseException. r?rnewman draft
authorNick Alexander <nalexander@mozilla.com>
Wed, 20 Jan 2016 17:18:55 -0800
changeset 327805 34d94568c1c6ee6c2b571a56a5a36b371a9115c2
parent 327804 1c362221f096ab0da8c338fae1dff2cf8e043fee
child 327806 d7529a9f8fadba0d30324ef2ca93be0999b71203
push id10307
push usernalexander@mozilla.com
push dateTue, 02 Feb 2016 01:08:05 +0000
reviewersrnewman
bugs1244944
milestone47.0a1
Bug 1244944 - Don't catch or throw ParseException. r?rnewman
mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java
mobile/android/services/src/main/java/org/mozilla/gecko/fxa/login/Married.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/CollectionKeys.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/MetaGlobal.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/SynchronizerConfiguration.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/MozResponse.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/RepositorySessionBundle.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/RepoUtils.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/ServerSyncStage.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryDataExtender.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCollectionKeys.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCommandProcessor.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCryptoRecord.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecord.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestResetCommands.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java
@@ -1,29 +1,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.browserid;
 
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.TreeMap;
-
 import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
 import org.mozilla.apache.commons.codec.binary.Base64;
 import org.mozilla.apache.commons.codec.binary.StringUtils;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
 
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.TreeMap;
+
 /**
  * Encode and decode JSON Web Tokens.
  * <p>
  * Reverse-engineered from the Node.js jwcrypto library at
  * <a href="https://github.com/mozilla/jwcrypto">https://github.com/mozilla/jwcrypto</a>
  * and informed by the informal draft standard "JSON Web Token (JWT)" at
  * <a href="http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html">http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html</a>.
  */
@@ -66,18 +64,17 @@ public class JSONWebTokenUtils {
     return payload;
   }
 
   /**
    * Public for testing.
    */
   @SuppressWarnings("unchecked")
   public static String getPayloadString(String payloadString, String audience, String issuer,
-      Long issuedAt, long expiresAt) throws NonObjectJSONException,
-      IOException, ParseException {
+      Long issuedAt, long expiresAt) throws NonObjectJSONException, IOException {
     ExtendedJSONObject payload;
     if (payloadString != null) {
       payload = new ExtendedJSONObject(payloadString);
     } else {
       payload = new ExtendedJSONObject();
     }
     if (audience != null) {
       payload.put("aud", audience);
@@ -86,27 +83,27 @@ public class JSONWebTokenUtils {
     if (issuedAt != null) {
       payload.put("iat", issuedAt);
     }
     payload.put("exp", expiresAt);
     // TreeMap so that keys are sorted. A small attempt to keep output stable over time.
     return JSONObject.toJSONString(new TreeMap<Object, Object>(payload.object));
   }
 
-  protected static String getCertificatePayloadString(VerifyingPublicKey publicKeyToSign, String email) throws NonObjectJSONException, IOException, ParseException  {
+  protected static String getCertificatePayloadString(VerifyingPublicKey publicKeyToSign, String email) throws NonObjectJSONException, IOException  {
     ExtendedJSONObject payload = new ExtendedJSONObject();
     ExtendedJSONObject principal = new ExtendedJSONObject();
     principal.put("email", email);
     payload.put("principal", principal);
     payload.put("public-key", publicKeyToSign.toJSONObject());
     return payload.toJSONString();
   }
 
   public static String createCertificate(VerifyingPublicKey publicKeyToSign, String email,
-      String issuer, long issuedAt, long expiresAt, SigningPrivateKey privateKey) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException  {
+      String issuer, long issuedAt, long expiresAt, SigningPrivateKey privateKey) throws NonObjectJSONException, IOException, GeneralSecurityException  {
     String certificatePayloadString = getCertificatePayloadString(publicKeyToSign, email);
     String payloadString = getPayloadString(certificatePayloadString, null, issuer, issuedAt, expiresAt);
     return JSONWebTokenUtils.encode(payloadString, privateKey);
   }
 
   /**
    * Create a Browser ID assertion.
    *
@@ -123,21 +120,20 @@ public class JSONWebTokenUtils {
    * @param issuedAt
    *          timestamp for assertion, in milliseconds since the epoch; if null,
    *          no timestamp is included.
    * @param expiresAt
    *          expiration timestamp for assertion, in milliseconds since the epoch.
    * @return assertion.
    * @throws NonObjectJSONException
    * @throws IOException
-   * @throws ParseException
    * @throws GeneralSecurityException
    */
   public static String createAssertion(SigningPrivateKey privateKeyToSignWith, String certificate, String audience,
-      String issuer, Long issuedAt, long expiresAt) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException  {
+      String issuer, Long issuedAt, long expiresAt) throws NonObjectJSONException, IOException, GeneralSecurityException  {
     String emptyAssertionPayloadString = "{}";
     String payloadString = getPayloadString(emptyAssertionPayloadString, audience, issuer, issuedAt, expiresAt);
     String signature = JSONWebTokenUtils.encode(payloadString, privateKeyToSignWith);
     return certificate + "~" + signature;
   }
 
   /**
    * For debugging only!
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/login/Married.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/login/Married.java
@@ -8,17 +8,16 @@ import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.security.GeneralSecurityException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.browserid.BrowserIDKeyPair;
 import org.mozilla.gecko.browserid.JSONWebTokenUtils;
 import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.ExecuteDelegate;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.LogMessage;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
@@ -50,17 +49,17 @@ public class Married extends TokensAndKe
     return o;
   }
 
   @Override
   public void execute(final ExecuteDelegate delegate) {
     delegate.handleTransition(new LogMessage("staying married"), this);
   }
 
-  public String generateAssertion(String audience, String issuer) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
+  public String generateAssertion(String audience, String issuer) throws NonObjectJSONException, IOException, GeneralSecurityException {
     // We generate assertions with no iat and an exp after 2050 to avoid
     // invalid-timestamp errors from the token server.
     final long expiresAt = JSONWebTokenUtils.DEFAULT_FUTURE_EXPIRES_AT_IN_MILLISECONDS;
     String assertion = JSONWebTokenUtils.createAssertion(keyPair.getPrivate(), certificate, audience, issuer, null, expiresAt);
     if (!FxAccountUtils.LOG_PERSONAL_INFORMATION) {
       return assertion;
     }
 
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CollectionKeys.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CollectionKeys.java
@@ -7,17 +7,16 @@ package org.mozilla.gecko.sync;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map.Entry;
 import java.util.Set;
 
 import org.json.simple.JSONArray;
-import org.json.simple.parser.ParseException;
 import org.mozilla.apache.commons.codec.binary.Base64;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 
 public class CollectionKeys {
   private KeyBundle                  defaultKeyBundle     = null;
   private final HashMap<String, KeyBundle> collectionKeyBundles = new HashMap<String, KeyBundle>();
 
@@ -103,17 +102,17 @@ public class CollectionKeys {
    *
    * @param keys
    *          A "crypto/keys" <code>CryptoRecord</code>, encrypted with
    *          <code>syncKeyBundle</code> if <code>syncKeyBundle</code> is non-null.
    * @param syncKeyBundle
    *          If non-null, the sync key bundle to decrypt <code>keys</code> with.
    */
   public void setKeyPairsFromWBO(CryptoRecord keys, KeyBundle syncKeyBundle)
-      throws CryptoException, IOException, ParseException, NonObjectJSONException {
+      throws CryptoException, IOException, NonObjectJSONException {
     if (keys == null) {
       throw new IllegalArgumentException("cannot set key pairs from null record");
     }
     if (syncKeyBundle != null) {
       keys.keyBundle = syncKeyBundle;
       keys.decrypt();
     }
     ExtendedJSONObject cleartext = keys.payload;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync;
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 
 import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
 import org.mozilla.apache.commons.codec.binary.Base64;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.CryptoInfo;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.crypto.MissingCryptoInputException;
 import org.mozilla.gecko.sync.crypto.NoKeyBundleException;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 import org.mozilla.gecko.sync.repositories.domain.RecordParseException;
@@ -82,17 +81,17 @@ public class CryptoRecord extends Record
     super(null, null, 0, false);
     if (payload == null) {
       throw new IllegalArgumentException(
           "No payload provided to CryptoRecord constructor.");
     }
     this.payload = payload;
   }
 
-  public CryptoRecord(String jsonString) throws IOException, ParseException, NonObjectJSONException {
+  public CryptoRecord(String jsonString) throws IOException, NonObjectJSONException {
 
     this(new ExtendedJSONObject(jsonString));
   }
 
   /**
    * Create a new CryptoRecord with the same metadata as an existing record.
    *
    * @param source
@@ -121,30 +120,29 @@ public class CryptoRecord extends Record
    *
    * and turn it into a CryptoRecord object.
    *
    * @param jsonRecord
    * @return
    *        A CryptoRecord that encapsulates the provided record.
    *
    * @throws NonObjectJSONException
-   * @throws ParseException
    * @throws IOException
    */
   public static CryptoRecord fromJSONRecord(String jsonRecord)
-      throws ParseException, NonObjectJSONException, IOException, RecordParseException {
+      throws NonObjectJSONException, IOException, RecordParseException {
     byte[] bytes = jsonRecord.getBytes("UTF-8");
     ExtendedJSONObject object = ExtendedJSONObject.parseUTF8AsJSONObject(bytes);
 
     return CryptoRecord.fromJSONRecord(object);
   }
 
   // TODO: defensive programming.
   public static CryptoRecord fromJSONRecord(ExtendedJSONObject jsonRecord)
-      throws IOException, ParseException, NonObjectJSONException, RecordParseException {
+      throws IOException, NonObjectJSONException, RecordParseException {
     String id                  = (String) jsonRecord.get(KEY_ID);
     String collection          = (String) jsonRecord.get(KEY_COLLECTION);
     String jsonEncodedPayload  = (String) jsonRecord.get(KEY_PAYLOAD);
 
     ExtendedJSONObject payload = new ExtendedJSONObject(jsonEncodedPayload);
 
     CryptoRecord record = new CryptoRecord(payload);
     record.guid         = id;
@@ -177,18 +175,17 @@ public class CryptoRecord extends Record
     // TODO: deleted?
     return record;
   }
 
   public void setKeyBundle(KeyBundle bundle) {
     this.keyBundle = bundle;
   }
 
-  public CryptoRecord decrypt() throws CryptoException, IOException, ParseException,
-                       NonObjectJSONException {
+  public CryptoRecord decrypt() throws CryptoException, IOException, NonObjectJSONException {
     if (keyBundle == null) {
       throw new NoKeyBundleException();
     }
 
     // Check that payload contains all pieces for crypto.
     if (!payload.containsKey(KEY_CIPHERTEXT) ||
         !payload.containsKey(KEY_IV) ||
         !payload.containsKey(KEY_HMAC)) {
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java
@@ -2,23 +2,22 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync;
 
 import android.content.Context;
 
 import org.json.simple.JSONArray;
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.delegates.FreshStartDelegate;
+import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
 import org.mozilla.gecko.sync.delegates.KeyUploadDelegate;
 import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
 import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.HttpResponseObserver;
 import org.mozilla.gecko.sync.net.SyncResponse;
@@ -97,17 +96,17 @@ public class GlobalSession implements Ht
   public URI wboURI(String collection, String id) throws URISyntaxException {
     return config.wboURI(collection, id);
   }
 
   public GlobalSession(SyncConfiguration config,
                        GlobalSessionCallback callback,
                        Context context,
                        ClientsDataDelegate clientsDelegate)
-    throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException {
+    throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
 
     if (callback == null) {
       throw new IllegalArgumentException("Must provide a callback to GlobalSession constructor.");
     }
 
     this.callback        = callback;
     this.context         = context;
     this.clientsDelegate = clientsDelegate;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/MetaGlobal.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/MetaGlobal.java
@@ -8,17 +8,16 @@ import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 import org.json.simple.JSONArray;
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalMalformedSyncIDException;
 import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalMalformedVersionException;
 import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
@@ -92,17 +91,17 @@ public class MetaGlobal implements SyncS
     ExtendedJSONObject payload = this.asRecordContents();
     CryptoRecord record = new CryptoRecord(payload);
     record.collection = "meta";
     record.guid       = "global";
     record.deleted    = false;
     return record;
   }
 
-  public void setFromRecord(CryptoRecord record) throws IllegalStateException, IOException, ParseException, NonObjectJSONException, NonArrayJSONException {
+  public void setFromRecord(CryptoRecord record) throws IllegalStateException, IOException, NonObjectJSONException, NonArrayJSONException {
     if (record == null) {
       throw new IllegalArgumentException("Cannot set meta/global from null record");
     }
     Logger.debug(LOG_TAG, "meta/global is " + record.payload.toJSONString());
     this.storageVersion = (Long) record.payload.get("storageVersion");
     this.syncID = (String) record.payload.get("syncID");
 
     setEngines(record.payload.getObject("engines"));
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/SynchronizerConfiguration.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/SynchronizerConfiguration.java
@@ -1,42 +1,41 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync;
 
-import java.io.IOException;
+import android.content.SharedPreferences.Editor;
 
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.PrefsBranch;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
 
-import android.content.SharedPreferences.Editor;
+import java.io.IOException;
 
 public class SynchronizerConfiguration {
   private static final String LOG_TAG = "SynczrConfiguration";
 
   public String syncID;
   public RepositorySessionBundle remoteBundle;
   public RepositorySessionBundle localBundle;
 
-  public SynchronizerConfiguration(PrefsBranch config) throws NonObjectJSONException, IOException, ParseException {
+  public SynchronizerConfiguration(PrefsBranch config) throws NonObjectJSONException, IOException {
     this.load(config);
   }
 
   public SynchronizerConfiguration(String syncID, RepositorySessionBundle remoteBundle, RepositorySessionBundle localBundle) {
     this.syncID       = syncID;
     this.remoteBundle = remoteBundle;
     this.localBundle  = localBundle;
   }
 
   // This should get partly shuffled back into SyncConfiguration, I think.
-  public void load(PrefsBranch config) throws NonObjectJSONException, IOException, ParseException {
+  public void load(PrefsBranch config) throws NonObjectJSONException, IOException {
     if (config == null) {
       throw new IllegalArgumentException("config cannot be null.");
     }
     String remoteJSON = config.getString("remote", null);
     String localJSON  = config.getString("local",  null);
     RepositorySessionBundle rB = new RepositorySessionBundle(remoteJSON);
     RepositorySessionBundle lB = new RepositorySessionBundle(localJSON);
     if (remoteJSON == null) {
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/MozResponse.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/MozResponse.java
@@ -6,17 +6,16 @@ package org.mozilla.gecko.sync.net;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.util.Scanner;
 
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.HttpStatus;
@@ -84,21 +83,19 @@ public class MozResponse {
 
   /**
    * Return the body as a <b>non-null</b> <code>ExtendedJSONObject</code>.
    *
    * @return A non-null <code>ExtendedJSONObject</code>.
    *
    * @throws IllegalStateException
    * @throws IOException
-   * @throws ParseException
    * @throws NonObjectJSONException
    */
-  public ExtendedJSONObject jsonObjectBody() throws IllegalStateException, IOException,
-                                 ParseException, NonObjectJSONException {
+  public ExtendedJSONObject jsonObjectBody() throws IllegalStateException, IOException, NonObjectJSONException {
     if (body != null) {
       // Do it from the cached String.
       return new ExtendedJSONObject(body);
     }
 
     HttpEntity entity = this.response.getEntity();
     if (entity == null) {
       throw new IOException("no entity");
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/RepositorySessionBundle.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/RepositorySessionBundle.java
@@ -1,29 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories;
 
-import java.io.IOException;
-
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 
+import java.io.IOException;
+
 public class RepositorySessionBundle {
   public static final String LOG_TAG = RepositorySessionBundle.class.getSimpleName();
 
   protected static final String JSON_KEY_TIMESTAMP = "timestamp";
 
   protected final ExtendedJSONObject object;
 
-  public RepositorySessionBundle(String jsonString) throws IOException, ParseException, NonObjectJSONException {
+  public RepositorySessionBundle(String jsonString) throws IOException, NonObjectJSONException {
 
     object = new ExtendedJSONObject(jsonString);
   }
 
   public RepositorySessionBundle(long lastSyncTimestamp) {
     object = new ExtendedJSONObject();
     this.setTimestamp(lastSyncTimestamp);
   }
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/RepoUtils.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/RepoUtils.java
@@ -1,32 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
-import java.io.IOException;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.os.RemoteException;
 
 import org.json.simple.JSONArray;
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
 
-import android.content.ContentProviderClient;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-import android.os.RemoteException;
+import java.io.IOException;
 
 public class RepoUtils {
 
   private static final String LOG_TAG = "RepoUtils";
 
   /**
    * A helper class for monotonous SQL querying. Does timing and logging,
    * offers a utility to throw on a null cursor.
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/ServerSyncStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/ServerSyncStage.java
@@ -1,20 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.stage;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
+import android.content.Context;
 
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.HTTPFailureException;
 import org.mozilla.gecko.sync.MetaGlobalException;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
@@ -38,17 +34,20 @@ import org.mozilla.gecko.sync.repositori
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.synchronizer.ServerLocalSynchronizer;
 import org.mozilla.gecko.sync.synchronizer.Synchronizer;
 import org.mozilla.gecko.sync.synchronizer.SynchronizerDelegate;
 import org.mozilla.gecko.sync.synchronizer.SynchronizerSession;
 
-import android.content.Context;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
 
 /**
  * Fetch from a server collection into a local repository, encrypting
  * and decrypting along the way.
  *
  * @author rnewman
  *
  */
@@ -116,17 +115,17 @@ public abstract class ServerSyncStage ex
       if (enabledInMetaGlobal != enabledInSelection) {
         // Engine enable state has been changed by the user.
         Logger.debug(LOG_TAG, "Engine state has been changed by user. Throwing exception.");
         throw new MetaGlobalException.MetaGlobalEngineStateChangedException(enabledInSelection);
       }
     }
   }
 
-  protected EngineSettings getEngineSettings() throws NonObjectJSONException, IOException, ParseException {
+  protected EngineSettings getEngineSettings() throws NonObjectJSONException, IOException {
     Integer version = getStorageVersion();
     if (version == null) {
       Logger.warn(LOG_TAG, "null storage version for " + this + "; using version 0.");
       version = 0;
     }
 
     SynchronizerConfiguration config = this.getConfig();
     if (config == null) {
@@ -162,25 +161,25 @@ public abstract class ServerSyncStage ex
     cryptoRepo.recordFactory = getRecordFactory();
     return cryptoRepo;
   }
 
   protected String bundlePrefix() {
     return this.getCollection() + ".";
   }
 
-  protected SynchronizerConfiguration getConfig() throws NonObjectJSONException, IOException, ParseException {
+  protected SynchronizerConfiguration getConfig() throws NonObjectJSONException, IOException {
     return new SynchronizerConfiguration(session.config.getBranch(bundlePrefix()));
   }
 
   protected void persistConfig(SynchronizerConfiguration synchronizerConfiguration) {
     synchronizerConfiguration.persist(session.config.getBranch(bundlePrefix()));
   }
 
-  public Synchronizer getConfiguredSynchronizer(GlobalSession session) throws NoCollectionKeysSetException, URISyntaxException, NonObjectJSONException, IOException, ParseException {
+  public Synchronizer getConfiguredSynchronizer(GlobalSession session) throws NoCollectionKeysSetException, URISyntaxException, NonObjectJSONException, IOException {
     Repository remote = wrappedServerRepo();
 
     Synchronizer synchronizer = new ServerLocalSynchronizer();
     synchronizer.repositoryA = remote;
     synchronizer.repositoryB = this.getLocalRepository();
     synchronizer.load(getConfig());
 
     return synchronizer;
@@ -544,17 +543,17 @@ public abstract class ServerSyncStage ex
     try {
       synchronizer = this.getConfiguredSynchronizer(session);
     } catch (NoCollectionKeysSetException e) {
       session.abort(e, "No CollectionKeys.");
       return;
     } catch (URISyntaxException e) {
       session.abort(e, "Invalid URI syntax for server repository.");
       return;
-    } catch (NonObjectJSONException | ParseException | IOException e) {
+    } catch (NonObjectJSONException | IOException e) {
       session.abort(e, "Invalid persisted JSON for config.");
       return;
     }
 
     Logger.debug(LOG_TAG, "Invoking synchronizer.");
     synchronizer.synchronize(session.getContext(), this);
     Logger.debug(LOG_TAG, "Reached end of execute.");
   }
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryDataExtender.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryDataExtender.java
@@ -1,47 +1,43 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.db;
 
-import java.io.IOException;
-import java.util.ArrayList;
+import android.database.Cursor;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
 import org.mozilla.gecko.background.sync.helpers.HistoryHelpers;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonArrayJSONException;
-import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryDataExtender;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils;
 import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
 
-import android.database.Cursor;
+import java.util.ArrayList;
 
 public class TestAndroidBrowserHistoryDataExtender extends AndroidSyncTestCase {
 
   protected AndroidBrowserHistoryDataExtender extender;
   protected static final String LOG_TAG = "SyncHistoryVisitsTest";
 
   public void setUp() {
     extender = new AndroidBrowserHistoryDataExtender(getApplicationContext());
     extender.wipe();
   }
 
   public void tearDown() {
     extender.close();
   }
 
-  public void testStoreFetch() throws NullCursorException, NonObjectJSONException, IOException, ParseException {
+  public void testStoreFetch() throws Exception {
     String guid = Utils.generateGuid();
     extender.store(Utils.generateGuid(), null);
     extender.store(guid, null);
     extender.store(Utils.generateGuid(), null);
 
     Cursor cur = null;
     try {
       cur = extender.fetch(guid);
@@ -50,17 +46,17 @@ public class TestAndroidBrowserHistoryDa
       assertEquals(guid, cur.getString(0));
     } finally {
       if (cur != null) {
         cur.close();
       }
     }
   }
 
-  public void testVisitsForGUID() throws NonArrayJSONException, NonObjectJSONException, IOException, ParseException, NullCursorException {
+  public void testVisitsForGUID() throws Exception {
     String guid = Utils.generateGuid();
     JSONArray visits = new ExtendedJSONObject("{ \"visits\": [ { \"key\" : \"value\" } ] }").getArray("visits");
 
     extender.store(Utils.generateGuid(), null);
     extender.store(guid, visits);
     extender.store(Utils.generateGuid(), null);
 
     JSONArray fetchedVisits = extender.visitsForGUID(guid);
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java
@@ -1,41 +1,35 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.sync;
 
-import java.io.IOException;
+import android.content.SharedPreferences;
 
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
 import org.mozilla.gecko.background.testhelpers.BaseMockServerSyncStage;
 import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback;
 import org.mozilla.gecko.background.testhelpers.MockRecord;
 import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
 import org.mozilla.gecko.background.testhelpers.WBORepository;
 import org.mozilla.gecko.background.testhelpers.WaitHelper;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.MetaGlobalException;
-import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
-import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 import org.mozilla.gecko.sync.stage.NoSuchStageException;
 import org.mozilla.gecko.sync.synchronizer.Synchronizer;
 
-import android.content.SharedPreferences;
-
 /**
  * Test the on-device side effects of reset operations on a stage.
  *
  * See also "TestResetCommands" in the unit test suite.
  */
 public class TestResetting extends AndroidSyncTestCase {
   private static final String TEST_USERNAME    = "johndoe";
   private static final String TEST_PASSWORD    = "password";
@@ -151,18 +145,17 @@ public class TestResetting extends Andro
           } catch (NoSuchStageException e) {
             performNotify(e);
           }
         }
       });
     }
   }
 
-  private GlobalSession createDefaultGlobalSession(final GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
-
+  private GlobalSession createDefaultGlobalSession(final GlobalSessionCallback callback) throws Exception {
     final KeyBundle keyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
     final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD);
     final SharedPreferences prefs = new MockSharedPreferences();
     final SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, authHeaderProvider, prefs);
     config.syncKeyBundle = keyBundle;
     return new GlobalSession(config, callback, getApplicationContext(), null) {
       @Override
       public boolean isEngineRemotelyEnabled(String engineName,
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
@@ -1,24 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.testhelpers;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
-
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
-import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
 import org.mozilla.gecko.sync.repositories.RecordFactory;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.stage.ServerSyncStage;
 
+import java.net.URISyntaxException;
+
 /**
  * A stage that joins two Repositories with no wrapping.
  */
 public abstract class BaseMockServerSyncStage extends ServerSyncStage {
 
   public Repository local;
   public Repository remote;
   public String name;
@@ -61,13 +58,12 @@ public abstract class BaseMockServerSync
   }
 
   @Override
   protected Repository wrappedServerRepo()
   throws NoCollectionKeysSetException, URISyntaxException {
     return getRemoteRepository();
   }
 
-  public SynchronizerConfiguration leakConfig()
-  throws NonObjectJSONException, IOException, ParseException {
+  public SynchronizerConfiguration leakConfig() throws Exception {
     return this.getConfig();
   }
 }
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
@@ -1,37 +1,36 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.testhelpers;
 
-import java.io.IOException;
-import java.util.HashMap;
-
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 import org.mozilla.gecko.sync.stage.CompletedStage;
 import org.mozilla.gecko.sync.stage.GlobalSyncStage;
 import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
 
+import java.io.IOException;
+import java.util.HashMap;
+
 
 public class MockGlobalSession extends MockPrefsGlobalSession {
 
-  public MockGlobalSession(String username, String password, KeyBundle keyBundle, GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException {
+  public MockGlobalSession(String username, String password, KeyBundle keyBundle, GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException {
     this(new SyncConfiguration(username, new BasicAuthHeaderProvider(username, password), new MockSharedPreferences(), keyBundle), callback);
   }
 
   public MockGlobalSession(SyncConfiguration config, GlobalSessionCallback callback)
-          throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException {
+          throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
     super(config, callback, null, null);
   }
 
   @Override
   public boolean isEngineRemotelyEnabled(String engine, EngineSettings engineSettings) {
     return false;
   }
 
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
@@ -1,60 +1,59 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.testhelpers;
 
-import java.io.IOException;
+import android.content.Context;
+import android.content.SharedPreferences;
 
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 
-import android.content.Context;
-import android.content.SharedPreferences;
+import java.io.IOException;
 
 /**
  * GlobalSession touches the Android prefs system. Stub that out.
  */
 public class MockPrefsGlobalSession extends GlobalSession {
 
   public MockSharedPreferences prefs;
 
   public MockPrefsGlobalSession(
       SyncConfiguration config, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
       throws SyncConfigurationException, IllegalArgumentException, IOException,
-      ParseException, NonObjectJSONException {
+      NonObjectJSONException {
     super(config, callback, context, clientsDelegate);
   }
 
   public static MockPrefsGlobalSession getSession(
       String username, String password,
       KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
       throws SyncConfigurationException, IllegalArgumentException, IOException,
-      ParseException, NonObjectJSONException {
+      NonObjectJSONException {
     return getSession(username, new BasicAuthHeaderProvider(username, password), null,
          syncKeyBundle, callback, context, clientsDelegate);
   }
 
   public static MockPrefsGlobalSession getSession(
       String username, AuthHeaderProvider authHeaderProvider, String prefsPath,
       KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
       throws SyncConfigurationException, IllegalArgumentException, IOException,
-      ParseException, NonObjectJSONException {
+      NonObjectJSONException {
 
     final SharedPreferences prefs = new MockSharedPreferences();
     final SyncConfiguration config = new SyncConfiguration(username, authHeaderProvider, prefs);
     config.syncKeyBundle = syncKeyBundle;
     return new MockPrefsGlobalSession(config, callback, context, clientsDelegate);
   }
 
   @Override
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java
@@ -1,17 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.android.sync.net.test;
 
 import ch.boye.httpclientandroidlib.HttpStatus;
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
 import org.junit.After;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
 import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
 import org.mozilla.android.sync.test.helpers.MockServer;
 import org.mozilla.android.sync.test.helpers.MockSyncClientsEngineStage;
 import org.mozilla.gecko.background.common.log.Logger;
@@ -56,24 +55,24 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 @RunWith(TestRunner.class)
 public class TestClientsEngineStage extends MockSyncClientsEngineStage {
   public final static String LOG_TAG = "TestClientsEngSta";
 
-  public TestClientsEngineStage() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException, URISyntaxException {
+  public TestClientsEngineStage() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException, URISyntaxException {
     super();
     session = initializeSession();
   }
 
   // Static so we can set it during the constructor. This is so evil.
   private static MockGlobalSessionCallback callback;
-  private static GlobalSession initializeSession() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException, URISyntaxException {
+  private static GlobalSession initializeSession() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException, URISyntaxException {
     callback = new MockGlobalSessionCallback();
     SyncConfiguration config = new SyncConfiguration(USERNAME, new BasicAuthHeaderProvider(USERNAME, PASSWORD), new MockSharedPreferences());
     config.syncKeyBundle = new KeyBundle(USERNAME, SYNC_KEY);
     GlobalSession session = new MockClientsGlobalSession(config, callback);
     session.config.setClusterURL(new URI(TEST_SERVER));
     session.config.setCollectionKeys(CollectionKeys.generateCollectionKeys());
     return session;
   }
@@ -173,17 +172,16 @@ public class TestClientsEngineStage exte
   public static class MockClientsGlobalSession extends MockGlobalSession {
     private ClientsDataDelegate clientsDataDelegate = new MockClientsDataDelegate();
 
     public MockClientsGlobalSession(SyncConfiguration config,
                                     GlobalSessionCallback callback)
         throws SyncConfigurationException,
                IllegalArgumentException,
                IOException,
-               ParseException,
                NonObjectJSONException {
       super(config, callback);
     }
 
     @Override
     public ClientsDataDelegate getClientsDelegate() {
       return clientsDataDelegate;
     }
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java
@@ -1,26 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.android.sync.net.test;
 
-import ch.boye.httpclientandroidlib.Header;
-import org.json.simple.parser.ParseException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 
+import ch.boye.httpclientandroidlib.Header;
+
 import static org.junit.Assert.assertEquals;
 
 /**
  * Test the transfer of a UTF-8 string from desktop, and ensure that it results in the
  * correct hashed Basic Auth header.
  */
 @RunWith(TestRunner.class)
 public class TestCredentialsEndToEnd {
@@ -41,17 +41,17 @@ public class TestCredentialsEndToEnd {
   @Test
   public void testUTF8() throws UnsupportedEncodingException {
     final String in  = "pïgéons1";
     final String out = "pïgéons1";
     assertEquals(out, Utils.decodeUTF8(in));
   }
 
   @Test
-  public void testAuthHeaderFromPassword() throws NonObjectJSONException, IOException, ParseException {
+  public void testAuthHeaderFromPassword() throws NonObjectJSONException, IOException {
     final ExtendedJSONObject parsed = new ExtendedJSONObject(DESKTOP_PASSWORD_JSON);
 
     final String password = parsed.getString("password");
     final String decoded = Utils.decodeUTF8(password);
 
     final byte[] expectedBytes = Utils.decodeBase64(BTOA_PASSWORD);
     final String expected = new String(expectedBytes, "UTF-8");
 
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
@@ -3,17 +3,16 @@
 
 package org.mozilla.android.sync.net.test;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.ProtocolVersion;
 import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
 import ch.boye.httpclientandroidlib.message.BasicStatusLine;
 import junit.framework.AssertionFailedError;
-import org.json.simple.parser.ParseException;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
 import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
 import org.mozilla.android.sync.test.helpers.MockResourceDelegate;
 import org.mozilla.android.sync.test.helpers.MockServer;
 import org.mozilla.gecko.background.testhelpers.MockAbstractNonRepositorySyncStage;
@@ -67,17 +66,17 @@ public class TestGlobalSession {
   private final String TEST_SYNC_KEY            = "abcdeabcdeabcdeabcdeabcdea";
   private final long   TEST_BACKOFF_IN_SECONDS  = 2401;
 
   public static WaitHelper getTestWaiter() {
     return WaitHelper.getTestWaiter();
   }
 
   @Test
-  public void testGetSyncStagesBy() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException, NoSuchStageException {
+  public void testGetSyncStagesBy() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException, NoSuchStageException {
 
     final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
     GlobalSession s = MockPrefsGlobalSession.getSession(TEST_USERNAME, TEST_PASSWORD,
                                                  new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY),
                                                  callback, /* context */ null, null);
 
     assertTrue(s.getSyncStageByName(Stage.syncBookmarks) instanceof AndroidBrowserBookmarksServerSyncStage);
 
@@ -235,17 +234,17 @@ public class TestGlobalSession {
           r.get();
         } catch (URISyntaxException e) {
           innerWaitHelper.performNotify(e);
         }
       }
     });
   }
 
-  public MockGlobalSessionCallback doTestSuccess(final boolean stageShouldBackoff, final boolean stageShouldAdvance) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
+  public MockGlobalSessionCallback doTestSuccess(final boolean stageShouldBackoff, final boolean stageShouldAdvance) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException {
     MockServer server = new MockServer() {
       @Override
       public void handle(Request request, Response response) {
         if (stageShouldBackoff) {
           response.addValue("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS));
         }
         super.handle(request, response);
       }
@@ -290,49 +289,49 @@ public class TestGlobalSession {
     assertFalse(BaseResource.isHttpResponseObserver(session));
 
     return callback;
   }
 
   @Test
   public void testOnSuccessBackoffAdvanced() throws SyncConfigurationException,
       IllegalArgumentException, NonObjectJSONException, IOException,
-      ParseException, CryptoException {
+      CryptoException {
     MockGlobalSessionCallback callback = doTestSuccess(true, true);
 
     assertTrue(callback.calledError); // TODO: this should be calledAborted.
     assertTrue(callback.calledRequestBackoff);
     assertEquals(1000 * TEST_BACKOFF_IN_SECONDS, callback.weaveBackoff);
   }
 
   @Test
   public void testOnSuccessBackoffAborted() throws SyncConfigurationException,
       IllegalArgumentException, NonObjectJSONException, IOException,
-      ParseException, CryptoException {
+      CryptoException {
     MockGlobalSessionCallback callback = doTestSuccess(true, false);
 
     assertTrue(callback.calledError); // TODO: this should be calledAborted.
     assertTrue(callback.calledRequestBackoff);
     assertEquals(1000 * TEST_BACKOFF_IN_SECONDS, callback.weaveBackoff);
   }
 
   @Test
   public void testOnSuccessNoBackoffAdvanced() throws SyncConfigurationException,
       IllegalArgumentException, NonObjectJSONException, IOException,
-      ParseException, CryptoException {
+      CryptoException {
     MockGlobalSessionCallback callback = doTestSuccess(false, true);
 
     assertTrue(callback.calledSuccess);
     assertFalse(callback.calledRequestBackoff);
   }
 
   @Test
   public void testOnSuccessNoBackoffAborted() throws SyncConfigurationException,
       IllegalArgumentException, NonObjectJSONException, IOException,
-      ParseException, CryptoException {
+      CryptoException {
     MockGlobalSessionCallback callback = doTestSuccess(false, false);
 
     assertTrue(callback.calledError); // TODO: this should be calledAborted.
     assertFalse(callback.calledRequestBackoff);
   }
 
   @Test
   public void testGenerateNewMetaGlobalNonePersisted() throws Exception {
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCollectionKeys.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCollectionKeys.java
@@ -1,15 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.android.sync.test;
 
 import org.json.simple.JSONArray;
-import org.json.simple.parser.ParseException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.apache.commons.codec.binary.Base64;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.mozilla.gecko.sync.CollectionKeys;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
@@ -66,49 +65,49 @@ public class TestCollectionKeys {
   }
 
   public static void assertSame(byte[] arrayOne, byte[] arrayTwo) {
     assertTrue(Arrays.equals(arrayOne, arrayTwo));
   }
 
 
   @Test
-  public void testSetKeysFromWBO() throws IOException, ParseException, NonObjectJSONException, CryptoException, NoCollectionKeysSetException {
+  public void testSetKeysFromWBO() throws IOException, NonObjectJSONException, CryptoException, NoCollectionKeysSetException {
     String json = "{\"default\":[\"3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=\",\"/AMaoCX4hzic28WY94XtokNi7N4T0nv+moS1y5wlbug=\"],\"collections\":{},\"collection\":\"crypto\",\"id\":\"keys\"}";
     CryptoRecord rec = new CryptoRecord(json);
 
     KeyBundle syncKeyBundle = new KeyBundle("slyjcrjednxd6rf4cr63vqilmkus6zbe", "6m8mv8ex2brqnrmsb9fjuvfg7y");
     rec.keyBundle = syncKeyBundle;
 
     rec.encrypt();
     CollectionKeys ck = new CollectionKeys();
     ck.setKeyPairsFromWBO(rec, syncKeyBundle);
     byte[] input = "3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=".getBytes("UTF-8");
     byte[] expected = Base64.decodeBase64(input);
     assertSame(expected, ck.defaultKeyBundle().getEncryptionKey());
   }
 
   @Test
-  public void testCryptoRecordFromCollectionKeys() throws CryptoException, NoCollectionKeysSetException, IOException, ParseException, NonObjectJSONException {
+  public void testCryptoRecordFromCollectionKeys() throws CryptoException, NoCollectionKeysSetException, IOException, NonObjectJSONException {
     CollectionKeys ck1 = CollectionKeys.generateCollectionKeys();
     assertNotNull(ck1.defaultKeyBundle());
     assertEquals(ck1.keyBundleForCollection("foobar"), ck1.defaultKeyBundle());
     CryptoRecord rec = ck1.asCryptoRecord();
     assertEquals(rec.collection, "crypto");
     assertEquals(rec.guid, "keys");
     JSONArray defaultKey = (JSONArray) rec.payload.get("default");
 
     assertSame(Base64.decodeBase64((String) (defaultKey.get(0))), ck1.defaultKeyBundle().getEncryptionKey());
     CollectionKeys ck2 = new CollectionKeys();
     ck2.setKeyPairsFromWBO(rec, null);
     assertSame(ck1.defaultKeyBundle().getEncryptionKey(), ck2.defaultKeyBundle().getEncryptionKey());
   }
 
   @Test
-  public void testCreateKeysBundle() throws CryptoException, NonObjectJSONException, IOException, ParseException, NoCollectionKeysSetException {
+  public void testCreateKeysBundle() throws CryptoException, NonObjectJSONException, IOException, NoCollectionKeysSetException {
     String username =                       "b6evr62dptbxz7fvebek7btljyu322wp";
     String friendlyBase32SyncKey =          "basuxv2426eqj7frhvpcwkavdi";
 
     KeyBundle syncKeyBundle = new KeyBundle(username, friendlyBase32SyncKey);
 
     CollectionKeys ck = CollectionKeys.generateCollectionKeys();
     CryptoRecord unencrypted = ck.asCryptoRecord();
     unencrypted.keyBundle = syncKeyBundle;
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCommandProcessor.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCommandProcessor.java
@@ -1,14 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.android.sync.test;
 
-import org.json.simple.parser.ParseException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.mozilla.gecko.sync.CommandProcessor;
 import org.mozilla.gecko.sync.CommandRunner;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.NonObjectJSONException;
@@ -44,70 +43,70 @@ public class TestCommandProcessor extend
 
     @Override
     public void executeCommand(final GlobalSession session, List<String> args) {
       commandExecuted = true;
     }
   }
 
   @Test
-  public void testRegisterCommand() throws NonObjectJSONException, IOException, ParseException {
+  public void testRegisterCommand() throws NonObjectJSONException, IOException {
     assertNull(commands.get(commandType));
     this.registerCommand(commandType, new MockCommandRunner(1));
     assertNotNull(commands.get(commandType));
   }
 
   @Test
-  public void testProcessRegisteredCommand() throws NonObjectJSONException, IOException, ParseException {
+  public void testProcessRegisteredCommand() throws NonObjectJSONException, IOException {
     commandExecuted = false;
     ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(wellFormedCommand);
     this.registerCommand(commandType, new MockCommandRunner(1));
     this.processCommand(session, unparsedCommand);
     assertTrue(commandExecuted);
   }
 
   @Test
-  public void testProcessUnregisteredCommand() throws NonObjectJSONException, IOException, ParseException {
+  public void testProcessUnregisteredCommand() throws NonObjectJSONException, IOException {
     commandExecuted = false;
     ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(wellFormedCommand);
     this.processCommand(session, unparsedCommand);
     assertFalse(commandExecuted);
   }
 
   @Test
-  public void testProcessInvalidCommand() throws NonObjectJSONException, IOException, ParseException {
+  public void testProcessInvalidCommand() throws NonObjectJSONException, IOException {
     ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(commandWithNoType);
     this.registerCommand(commandType, new MockCommandRunner(1));
     this.processCommand(session, unparsedCommand);
     assertFalse(commandExecuted);
   }
 
   @Test
-  public void testParseCommandNoType() throws NonObjectJSONException, IOException, ParseException {
+  public void testParseCommandNoType() throws NonObjectJSONException, IOException {
     ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(commandWithNoType);
     assertNull(CommandProcessor.parseCommand(unparsedCommand));
   }
 
   @Test
-  public void testParseCommandNoArgs() throws NonObjectJSONException, IOException, ParseException {
+  public void testParseCommandNoArgs() throws NonObjectJSONException, IOException {
     ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(commandWithNoArgs);
     assertNull(CommandProcessor.parseCommand(unparsedCommand));
   }
 
   @Test
-  public void testParseWellFormedCommand() throws NonObjectJSONException, IOException, ParseException {
+  public void testParseWellFormedCommand() throws NonObjectJSONException, IOException {
     ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(wellFormedCommand);
     Command parsedCommand = CommandProcessor.parseCommand(unparsedCommand);
     assertNotNull(parsedCommand);
     assertEquals(2, parsedCommand.args.size());
     assertEquals(commandType, parsedCommand.commandType);
   }
 
   @Test
-  public void testParseCommandNullArg() throws NonObjectJSONException, IOException, ParseException {
+  public void testParseCommandNullArg() throws NonObjectJSONException, IOException {
     ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(wellFormedCommandWithNullArgs);
     Command parsedCommand = CommandProcessor.parseCommand(unparsedCommand);
     assertNotNull(parsedCommand);
     assertEquals(4, parsedCommand.args.size());
     assertEquals(commandType, parsedCommand.commandType);
     final List<String> expectedArgs = new ArrayList<String>();
     expectedArgs.add("https://bugzilla.mozilla.org/show_bug.cgi?id=731341");
     expectedArgs.add(null);
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCryptoRecord.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCryptoRecord.java
@@ -1,16 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.android.sync.test;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.apache.commons.codec.binary.Base64;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
@@ -30,17 +29,17 @@ import static org.junit.Assert.assertNul
 import static org.junit.Assert.assertTrue;
 
 @RunWith(TestRunner.class)
 public class TestCryptoRecord {
   String base64EncryptionKey = "9K/wLdXdw+nrTtXo4ZpECyHFNr4d7aYHqeg3KW9+m6Q=";
   String base64HmacKey = "MMntEfutgLTc8FlTLQFms8/xMPmCldqPlq/QQXEjx70=";
 
   @Test
-  public void testBaseCryptoRecordEncrypt() throws IOException, ParseException, NonObjectJSONException, CryptoException {
+  public void testBaseCryptoRecordEncrypt() throws IOException, NonObjectJSONException, CryptoException {
 
     ExtendedJSONObject clearPayload = new ExtendedJSONObject("{\"id\":\"5qRsgXWRJZXr\"," +
             "\"title\":\"Index of file:///Users/jason/Library/Application " +
             "Support/Firefox/Profiles/ksgd7wpk.LocalSyncServer/weave/logs/\"," +
             "\"histUri\":\"file:///Users/jason/Library/Application%20Support/Firefox/Profiles" +
             "/ksgd7wpk.LocalSyncServer/weave/logs/\",\"visits\":[{\"type\":1," +
             "\"date\":1319149012372425}]}");
 
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecord.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecord.java
@@ -1,16 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.android.sync.test;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.gecko.background.db.Tab;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
@@ -28,17 +27,17 @@ import static org.junit.Assert.assertFal
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 @RunWith(TestRunner.class)
 public class TestRecord {
 
   @SuppressWarnings("static-method")
   @Test
-  public void testQueryRecord() throws NonObjectJSONException, IOException, ParseException {
+  public void testQueryRecord() throws NonObjectJSONException, IOException {
     final String expectedGUID = "Bl3n3gpKag3s";
     final String testRecord =
         "{\"id\":\"" + expectedGUID + "\"," +
         " \"type\":\"query\"," +
         " \"title\":\"Downloads\"," +
         " \"parentName\":\"\"," +
         " \"bmkUri\":\"place:transition=7&sort=4\"," +
         " \"tags\":[]," +
@@ -275,34 +274,34 @@ public class TestRecord {
          "\"mNTdpgoRZMbW\", \"-L8Vci6CbkJY\", \"bVzudKSQERc1\", \"Gxl9lb4DXsmL\"," +
          "\"3Qr13GucOtEh\"]}";
 
   public class PayloadBookmarkRecord extends BookmarkRecord {
     public PayloadBookmarkRecord() {
       super("abcdefghijkl", "bookmarks", 1234, false);
     }
 
-    public void doTest() throws NonObjectJSONException, IOException, ParseException {
+    public void doTest() throws NonObjectJSONException, IOException {
       this.initFromPayload(new ExtendedJSONObject(payload));
       assertEquals("abcdefghijkl",      this.guid);              // Ignores payload.
       assertEquals("livemark",          this.type);
       assertEquals("Bookmarks Toolbar", this.parentName);
       assertEquals("toolbar",           this.parentID);
       assertEquals("",                  this.description);
       assertEquals(null,                this.children);
 
       final String encodedSite = "http%3A%2F%2Fwww.bbc.co.uk%2Fgo%2Frss%2Fint%2Fnews%2F-%2Fnews%2F";
       final String encodedFeed = "http%3A%2F%2Ffxfeeds.mozilla.com%2Fen-US%2Ffirefox%2Fheadlines.xml";
       final String expectedURI = "places:siteUri=" + encodedSite + "&feedUri=" + encodedFeed;
       assertEquals(expectedURI, this.bookmarkURI);
     }
   }
 
   @Test
-  public void testUnusualBookmarkRecords() throws NonObjectJSONException, IOException, ParseException {
+  public void testUnusualBookmarkRecords() throws NonObjectJSONException, IOException {
     PayloadBookmarkRecord record = new PayloadBookmarkRecord();
     record.doTest();
   }
 
   @SuppressWarnings("static-method")
   @Test
   public void testTTL() {
     Record record = new HistoryRecord();
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestResetCommands.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestResetCommands.java
@@ -1,15 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.android.sync.test;
 
 import android.content.SharedPreferences;
-import org.json.simple.parser.ParseException;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback;
 import org.mozilla.gecko.background.testhelpers.MockPrefsGlobalSession;
 import org.mozilla.gecko.background.testhelpers.MockServerSyncStage;
 import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
@@ -57,17 +56,17 @@ public class TestResetCommands {
   }
 
   @Before
   public void setUp() {
     assertTrue(WaitHelper.getTestWaiter().isIdle());
   }
 
   @Test
-  public void testHandleResetCommand() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
+  public void testHandleResetCommand() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException {
     // Create a global session.
     // Set up stage mappings for a real stage name (because they're looked up by name
     // in an enumeration) pointing to our fake stage.
     // Send a reset command.
     // Verify that reset is called on our stage.
 
     class Result {
       public boolean called = false;
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
@@ -1,14 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.testhelpers;
 
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
 import org.mozilla.gecko.sync.repositories.RecordFactory;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.stage.ServerSyncStage;
 
 import java.io.IOException;
@@ -62,12 +61,12 @@ public abstract class BaseMockServerSync
 
   @Override
   protected Repository wrappedServerRepo()
   throws NoCollectionKeysSetException, URISyntaxException {
     return getRemoteRepository();
   }
 
   public SynchronizerConfiguration leakConfig()
-  throws NonObjectJSONException, IOException, ParseException {
+  throws NonObjectJSONException, IOException {
     return this.getConfig();
   }
 }
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
@@ -1,14 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.testhelpers;
 
-import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 import org.mozilla.gecko.sync.stage.CompletedStage;
@@ -16,22 +15,22 @@ import org.mozilla.gecko.sync.stage.Glob
 import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
 
 import java.io.IOException;
 import java.util.HashMap;
 
 
 public class MockGlobalSession extends MockPrefsGlobalSession {
 
-  public MockGlobalSession(String username, String password, KeyBundle keyBundle, GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException {
+  public MockGlobalSession(String username, String password, KeyBundle keyBundle, GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException {
     this(new SyncConfiguration(username, new BasicAuthHeaderProvider(username, password), new MockSharedPreferences(), keyBundle), callback);
   }
 
   public MockGlobalSession(SyncConfiguration config, GlobalSessionCallback callback)
-          throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException {
+          throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
     super(config, callback, null, null);
   }
 
   @Override
   public boolean isEngineRemotelyEnabled(String engine, EngineSettings engineSettings) {
     return false;
   }
 
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.background.testhelpers;
 
 import android.content.Context;
 import android.content.SharedPreferences;
-import org.json.simple.parser.ParseException;
+
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
@@ -23,37 +23,34 @@ import java.io.IOException;
  */
 public class MockPrefsGlobalSession extends GlobalSession {
 
   public MockSharedPreferences prefs;
 
   public MockPrefsGlobalSession(
       SyncConfiguration config, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
-      throws SyncConfigurationException, IllegalArgumentException, IOException,
-      ParseException, NonObjectJSONException {
+      throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
     super(config, callback, context, clientsDelegate);
   }
 
   public static MockPrefsGlobalSession getSession(
       String username, String password,
       KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
-      throws SyncConfigurationException, IllegalArgumentException, IOException,
-      ParseException, NonObjectJSONException {
+      throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
     return getSession(username, new BasicAuthHeaderProvider(username, password), null,
          syncKeyBundle, callback, context, clientsDelegate);
   }
 
   public static MockPrefsGlobalSession getSession(
       String username, AuthHeaderProvider authHeaderProvider, String prefsPath,
       KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
-      throws SyncConfigurationException, IllegalArgumentException, IOException,
-      ParseException, NonObjectJSONException {
+      throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
 
     final SharedPreferences prefs = new MockSharedPreferences();
     final SyncConfiguration config = new SyncConfiguration(username, authHeaderProvider, prefs);
     config.syncKeyBundle = syncKeyBundle;
     return new MockPrefsGlobalSession(config, callback, context, clientsDelegate);
   }
 
   @Override
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java
@@ -1,15 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.sync.middleware.test;
 
 import junit.framework.AssertionFailedError;
-import org.json.simple.parser.ParseException;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionBeginDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionCreationDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionFetchRecordsDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionFinishDelegate;
 import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionStoreDelegate;
@@ -156,17 +155,17 @@ public class TestCrypto5MiddlewareReposi
     }));
     assertEquals(0, wboRepo.wbos.size());
   }
 
   @Test
   /**
    * Verify that store is actually writing encrypted data to the underlying repository.
    */
-  public void testStoreEncrypts() throws NonObjectJSONException, CryptoException, IOException, ParseException {
+  public void testStoreEncrypts() throws NonObjectJSONException, CryptoException, IOException {
     final BookmarkRecord record = new BookmarkRecord("nncdefghiaaa", "coll", System.currentTimeMillis(), false);
     record.title = "unencrypted title";
 
     runInOnBeginSucceeded(new Runnable() {
       @Override public void run() {
         try {
           try {
             cmwSession.setStoreDelegate(new ExpectSuccessRepositorySessionStoreDelegate(getTestWaiter()));
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java
@@ -1,15 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.sync.stage.test;
 
 import org.json.simple.JSONArray;
-import org.json.simple.parser.ParseException;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.android.sync.net.test.TestMetaGlobal;
 import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
 import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
 import org.mozilla.android.sync.test.helpers.MockServer;
 import org.mozilla.gecko.background.testhelpers.MockGlobalSession;
@@ -345,17 +344,17 @@ public class TestFetchMetaGlobalStage {
       public void run() {
         session.freshStart();
       }
     }));
     data.stopHTTPServer();
   }
 
   @Test
-  public void testFreshStart() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
+  public void testFreshStart() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException {
     final AtomicBoolean mgUploaded = new AtomicBoolean(false);
     final AtomicBoolean mgDownloaded = new AtomicBoolean(false);
     final MetaGlobal uploadedMg = new MetaGlobal(null, null);
 
     MockServer server = new MockServer() {
       @Override
       public void handle(Request request, Response response) {
         if (request.getMethod().equals("PUT")) {
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java
@@ -1,16 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.gecko.sync.test;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mozilla.gecko.background.testhelpers.TestRunner;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.UnexpectedJSONException.BadRequiredFieldJSONException;
 
@@ -29,32 +28,32 @@ import static org.junit.Assert.assertTru
 import static org.junit.Assert.fail;
 
 @RunWith(TestRunner.class)
 public class TestExtendedJSONObject {
   public static String exampleJSON = "{\"modified\":1233702554.25,\"success\":[\"{GXS58IDC}12\",\"{GXS58IDC}13\",\"{GXS58IDC}15\",\"{GXS58IDC}16\",\"{GXS58IDC}18\",\"{GXS58IDC}19\"],\"failed\":{\"{GXS58IDC}11\":[\"invalid parentid\"],\"{GXS58IDC}14\":[\"invalid parentid\"],\"{GXS58IDC}17\":[\"invalid parentid\"],\"{GXS58IDC}20\":[\"invalid parentid\"]}}";
   public static String exampleIntegral = "{\"modified\":1233702554,}";
 
   @Test
-  public void testFractional() throws IOException, ParseException, NonObjectJSONException {
+  public void testFractional() throws IOException, NonObjectJSONException {
     ExtendedJSONObject o = new ExtendedJSONObject(exampleJSON);
     assertTrue(o.containsKey("modified"));
     assertTrue(o.containsKey("success"));
     assertTrue(o.containsKey("failed"));
     assertFalse(o.containsKey(" "));
     assertFalse(o.containsKey(""));
     assertFalse(o.containsKey("foo"));
     assertTrue(o.get("modified") instanceof Number);
     assertTrue(o.get("modified").equals(Double.parseDouble("1233702554.25")));
     assertEquals(Long.valueOf(1233702554250L), o.getTimestamp("modified"));
     assertEquals(null, o.getTimestamp("foo"));
   }
 
   @Test
-  public void testIntegral() throws IOException, ParseException, NonObjectJSONException {
+  public void testIntegral() throws IOException, NonObjectJSONException {
     ExtendedJSONObject o = new ExtendedJSONObject(exampleIntegral);
     assertTrue(o.containsKey("modified"));
     assertFalse(o.containsKey("success"));
     assertTrue(o.get("modified") instanceof Number);
     assertTrue(o.get("modified").equals(Long.parseLong("1233702554")));
     assertEquals(Long.valueOf(1233702554000L), o.getTimestamp("modified"));
     assertEquals(null, o.getTimestamp("foo"));
   }