Repository: firebase/firebase-admin-java
Pull request #159 (2018-03-29 05:16:52)

Reading FCM error code from the details section
Porting error handling improvement from https://github.com/firebase/firebase-admin-node/pull/246

Reading error code from the `details` section of the HTTP response when available.


Patch:
diff --git a/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java b/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java
index c068004..21ab389 100644
--- a/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java
+++ b/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java
@@ -58,6 +58,8 @@ import java.util.concurrent.Callable;
 public class FirebaseMessaging {
 
   private static final String FCM_URL = "https://fcm.googleapis.com/v1/projects/%s/messages:send";
+  private static final String FCM_ERROR_TYPE =
+      "type.googleapis.com/google.firebase.fcm.v1.FcmErrorCode";
 
   private static final String INTERNAL_ERROR = "internal-error";
   private static final String UNKNOWN_ERROR = "unknown-error";
@@ -261,11 +263,11 @@ public class FirebaseMessaging {
       // ignored
     }
 
-    String code = FCM_ERROR_CODES.get(response.getString("status"));
+    String code = FCM_ERROR_CODES.get(response.getErrorCode());
     if (code == null) {
       code = UNKNOWN_ERROR;
     }
-    String msg = response.getString("message");
+    String msg = response.getErrorMessage();
     if (Strings.isNullOrEmpty(msg)) {
       msg = String.format("Unexpected HTTP response with status: %d; body: %s",
           e.getStatusCode(), e.getContent());
@@ -388,9 +390,27 @@ public class FirebaseMessaging {
     private Map<String, Object> error;
 
 
-    String getString(String key) {
+    String getErrorCode() {
+      if (error == null) {
+        return null;
+      }
+      Object details = error.get("details");
+      if (details != null && details instanceof List) {
+        for (Object detail : (List) details) {
+          if (detail instanceof Map) {
+            Map detailMap = (Map) detail;
+            if (FCM_ERROR_TYPE.equals(detailMap.get("@type"))) {
+              return (String) detailMap.get("errorCode");
+            }
+          }
+        }
+      }
+      return (String) error.get("status");
+    }
+
+    String getErrorMessage() {
       if (error != null) {
-        return (String) error.get(key);
+        return (String) error.get("message");
       }
       return null;
     }


Test patch:
diff --git a/src/test/java/com/google/firebase/messaging/FirebaseMessagingTest.java b/src/test/java/com/google/firebase/messaging/FirebaseMessagingTest.java
index 3eb1545..2872d8a 100644
--- a/src/test/java/com/google/firebase/messaging/FirebaseMessagingTest.java
+++ b/src/test/java/com/google/firebase/messaging/FirebaseMessagingTest.java
@@ -97,7 +97,7 @@ public class FirebaseMessagingTest {
   }
 
   @Test
-  public void testNullMessage() throws Exception {
+  public void testNullMessage() {
     FirebaseMessaging messaging = initDefaultMessaging();
     TestResponseInterceptor interceptor = new TestResponseInterceptor();
     messaging.setInterceptor(interceptor);
@@ -218,6 +218,31 @@ public class FirebaseMessagingTest {
     }
   }
 
+  @Test
+  public void testSendErrorWithFcmErrorCode() throws Exception {
+    MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
+    FirebaseMessaging messaging = initMessaging(response);
+    for (int code : HTTP_ERRORS) {
+      response.setStatusCode(code).setContent(
+          "{\"error\": {\"status\": \"INVALID_ARGUMENT\", \"message\": \"test error\", "
+              + "\"details\":[{\"@type\": \"type.googleapis.com/google.firebase.fcm"
+              + ".v1.FcmErrorCode\", \"errorCode\": \"UNREGISTERED\"}]}}");
+      TestResponseInterceptor interceptor = new TestResponseInterceptor();
+      messaging.setInterceptor(interceptor);
+      try {
+        messaging.sendAsync(Message.builder().setTopic("test-topic").build()).get();
+        fail("No error thrown for HTTP error");
+      } catch (ExecutionException e) {
+        assertTrue(e.getCause() instanceof FirebaseMessagingException);
+        FirebaseMessagingException error = (FirebaseMessagingException) e.getCause();
+        assertEquals("registration-token-not-registered", error.getErrorCode());
+        assertEquals("test error", error.getMessage());
+        assertTrue(error.getCause() instanceof HttpResponseException);
+      }
+      checkRequestHeader(interceptor);
+    }
+  }
+
   @Test
   public void testInvalidSubscribe() {
     FirebaseMessaging messaging = initDefaultMessaging();