Repository: slackapi/java-slack-sdk
Issue: Code breaks on receiving "user_change" event

### Issue Type

- [x] Bug
- [ ] Enhancement / Feature request
- [ ] Question
- [ ] Documentation

### Description

When user_change event is sent, the code breaks with the following exception

```
java.lang.UnsupportedOperationException: JsonObject

	at com.google.gson.JsonElement.getAsString(JsonElement.java:179)
	at com.slack.api.bolt.middleware.builtin.IgnoringSelfEvents.apply(IgnoringSelfEvents.java:79)
```

This happens because code expects `user` to contain string but it contained jsonObject

```
{
    "token": ".....",
    "team_id": ".....",
    "enterprise_id": "....",
    "api_app_id": "....",
    "event": {
        "type": "user_change",
        "user": {
            "id": "....",
            "name": "gaurav",
......
}
```

---

The issue is reproducible in:
* Module Version: 1.0.0
* JDK Version: 1.8.0_231

The steps to reproduce are:
1. subscribe to user_change event
2. Change any field to produce webhook

The expected result is:
Event to get handled

The actual result is:
exception is thrown

---

* [x] I've read and understood the [Contributing guidelines](https://github.com/slackapi/java-slack-sdk/blob/master/.github/contributing.md) and have done my best effort to follow them.
* [x] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
* [x] I've searched for any related issues and avoided creating a duplicate issue.

Changed files:
bolt/src/test/java/test_locally/middleware/IgnoringSelfEventsTest.java, bolt/src/main/java/com/slack/api/bolt/middleware/builtin/IgnoringSelfEvents.java

diff --git a/bolt/src/main/java/com/slack/api/bolt/middleware/builtin/IgnoringSelfEvents.java b/bolt/src/main/java/com/slack/api/bolt/middleware/builtin/IgnoringSelfEvents.java
index 5e77cf63..8067ed55 100644
--- a/bolt/src/main/java/com/slack/api/bolt/middleware/builtin/IgnoringSelfEvents.java
+++ b/bolt/src/main/java/com/slack/api/bolt/middleware/builtin/IgnoringSelfEvents.java
@@ -1,5 +1,13 @@
 package com.slack.api.bolt.middleware.builtin;
 
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
 import com.google.gson.Gson;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
@@ -16,13 +24,6 @@ import com.slack.api.methods.response.bots.BotsInfoResponse;
 import com.slack.api.model.event.MemberJoinedChannelEvent;
 import com.slack.api.model.event.MemberLeftChannelEvent;
 import com.slack.api.util.json.GsonFactory;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 
 /**
  * Filters some events that may be generated by this app for Events API.
@@ -75,7 +76,14 @@ public class IgnoringSelfEvents implements Middleware {
             JsonObject eventElem = extractEventElem(eventRequest.getRequestBodyAsString());
             if (eventElem != null) {
                 JsonElement eventUserIdElem = eventElem.get("user");
-                String eventBotUserId = eventUserIdElem != null ? eventUserIdElem.getAsString() : null;
+                String eventBotUserId = null;
+                if (eventUserIdElem != null) {
+                    if (eventUserIdElem.isJsonObject()) {
+                        eventBotUserId = eventUserIdElem.getAsJsonObject().get("id").getAsString();
+                    } else {
+                        eventBotUserId = eventUserIdElem.getAsString();
+                    }
+                }
                 JsonElement botIdElem = eventElem.get("bot_id");
                 if (eventBotUserId == null && botIdElem != null) {
                     String botId = botIdElem.getAsString();
diff --git a/bolt/src/test/java/test_locally/middleware/IgnoringSelfEventsTest.java b/bolt/src/test/java/test_locally/middleware/IgnoringSelfEventsTest.java
index 8d3f4380..e375f776 100644
--- a/bolt/src/test/java/test_locally/middleware/IgnoringSelfEventsTest.java
+++ b/bolt/src/test/java/test_locally/middleware/IgnoringSelfEventsTest.java
@@ -1,29 +1,36 @@
 package test_locally.middleware;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static util.MockSlackApi.InvalidToken;
+import static util.MockSlackApi.ValidToken;
+
+import util.MockSlackApiServer;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+
 import com.slack.api.Slack;
 import com.slack.api.SlackConfig;
 import com.slack.api.app_backend.events.payload.MemberJoinedChannelPayload;
 import com.slack.api.app_backend.events.payload.MessagePayload;
+import com.slack.api.app_backend.events.payload.UserChangePayload;
 import com.slack.api.bolt.middleware.MiddlewareChain;
 import com.slack.api.bolt.middleware.builtin.IgnoringSelfEvents;
 import com.slack.api.bolt.request.RequestHeaders;
 import com.slack.api.bolt.request.builtin.EventRequest;
 import com.slack.api.bolt.response.Response;
 import com.slack.api.methods.MethodsClient;
+import com.slack.api.model.User;
 import com.slack.api.model.event.MemberJoinedChannelEvent;
 import com.slack.api.model.event.MessageEvent;
+import com.slack.api.model.event.UserChangeEvent;
 import com.slack.api.util.json.GsonFactory;
-import org.junit.Test;
-import util.MockSlackApiServer;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.Assert.*;
-import static util.MockSlackApi.InvalidToken;
-import static util.MockSlackApi.ValidToken;
 
 public class IgnoringSelfEventsTest {
 
@@ -77,6 +84,30 @@ public class IgnoringSelfEventsTest {
         assertEquals(404L, result.getStatusCode().longValue());
     }
 
+    @Test
+    public void ignored_withUserObject() throws Exception {
+        IgnoringSelfEvents middleware = new IgnoringSelfEvents(SlackConfig.DEFAULT) {
+            @Override
+            public String findAndSaveBotUserId(MethodsClient client, String botId) {
+                return "U123BOT";
+            }
+        };
+        Map<String, List<String>> rawHeaders = new HashMap<>();
+        RequestHeaders headers = new RequestHeaders(rawHeaders);
+        UserChangePayload payload = new UserChangePayload();
+        payload.setTeamId("T123");
+        UserChangeEvent event = new UserChangeEvent();
+        User user = new User();
+        user.setId("U123BOT");
+        event.setUser(user);
+        payload.setEvent(event);
+        EventRequest req = new EventRequest(GsonFactory.createSnakeCase().toJson(payload), headers);
+        req.getContext().setBotUserId("U123BOT");
+        Response resp = new Response();
+        Response result = middleware.apply(req, resp, chain);
+        assertEquals(200L, result.getStatusCode().longValue());
+    }
+
     @Test
     public void not_ignored_no_botUserId() throws Exception {
         IgnoringSelfEvents middleware = new IgnoringSelfEvents(SlackConfig.DEFAULT) {