Repository: appium/java-client
Issue: Appium 1.7.0 crashes Java client 5.0.3 when testing iOS

## Description

When attempting to use java-client 5.0.3 to test an iOS device with Appium 1.7.0, the java-client crashes with java.lang.NullPointerException: null value in entry: browserName=null

## Environment

* java client build version or git revision if you use some shapshot: 5.0.3
* Appium server version or git revision if you use some shapshot: 1.7.0
* Desktop OS/version used to run Appium if necessary: macOS Sierra 10.12.6
* Node.js version (unless using Appium.app|exe) or Appium CLI or Appium.app|exe: Node.js v8.5.0, Appium 1.7.0
* Mobile platform/version under test: iOS
* Real device or emulator/simulator: Real Device

## Details

Using the same Appium Server, I can use appium-desktop using the custom server option to connect to the iOS device just fine. Android is unaffected. I believe this chunk of the logs are could relevant:

```
2017-09-19 22:43:55:863 - info: [HTTP] <-- POST /wd/hub/session 200 23221 ms - 589 
2017-09-19 22:43:55:908 - info: [HTTP] --> GET /wd/hub/session/c4c0364a-9a80-442e-b328-3dbb5d77418b {}
2017-09-19 22:43:55:909 - info: [debug] [MJSONWP] Calling AppiumDriver.getSession() with args: ["c4c0364a-9a80-442e-b328-3dbb5d77418b"]
2017-09-19 22:43:55:909 - info: [debug] [XCUITest] Executing command 'getSession'
2017-09-19 22:43:55:924 - info: [debug] [JSONWP Proxy] Proxying [GET /] to [GET http://localhost:8100/session/25E38EC3-E56F-44E4-806E-9B404F0A9D80] with no body
2017-09-19 22:43:56:103 - info: [debug] [JSONWP Proxy] Got response with status 200: "{\\n  \\"value\\" : {\\n    \\"sessionId\\" : \\"25E38EC3-E56F-44E4-806E-9B404F0A9D80\\",\\n    \\"capabilities\\" : {\\n      \\"device\\" : \\"iphone\\",\\n      \\"browserName\\" : null,\\n      \\"sdkVersion\\" : \\"10.3.2\\",\\n      \\"CFBundleIdentifier\\" : \\"local.pid.53\\"\\n    }\\n  },\\n  \\"sessionId\\" : \\"25E38EC3-E56F-44E4-806E-9B404F0A9D80\\",\\n  \\"status\\" : 0\\n}"
2017-09-19 22:43:56:103 - info: [XCUITest] Merging WDA caps over Appium caps for session detail response
2017-09-19 22:43:56:104 - info: [debug] [MJSONWP] Responding to client with driver.getSession() result: {"udid":"67e44e99a952683ca27e8beccc50687bf4a71490","app":"/Users/nwelna/Documents/app-automation/appFiles/ios/app.ipa","xcodeOrgId":"UTURYJS693","automationName":"XCUITest","browserName":null,"platformName":"iOS","deviceName":"Test Device","xcodeSigningId":"iPhone Developer","usePrebuiltWDA":true,"device":"iphone","sdkVersion":"10.3.2","CFBundleIdentifier":"local.pid.53"}
2017-09-19 22:43:56:105 - info: [HTTP] <-- GET /wd/hub/session/c4c0364a-9a80-442e-b328-3dbb5d77418b 200 196 ms - 486 
2017-09-19 22:43:56:196 - info: [Appium] Received SIGTERM - shutting down
```


## Code To Reproduce Issue [ Good To Have ]

Just attempt to connect to a real iOS device

## Ecxeption stacktraces

[gist](https://gist.github.com/welnanick/2e553ea885185829c7e589dee45f71bd)



Changed files:
src/main/java/io/appium/java_client/AppiumDriver.java, src/main/java/io/appium/java_client/HasSessionDetails.java

diff --git a/src/main/java/io/appium/java_client/AppiumDriver.java b/src/main/java/io/appium/java_client/AppiumDriver.java
index be4900a2..dc7df872 100644
--- a/src/main/java/io/appium/java_client/AppiumDriver.java
+++ b/src/main/java/io/appium/java_client/AppiumDriver.java
@@ -17,9 +17,8 @@
 package io.appium.java_client;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static io.appium.java_client.remote.MobileCapabilityType.AUTOMATION_NAME;
 import static io.appium.java_client.remote.MobileCapabilityType.PLATFORM_NAME;
-import static java.util.Optional.ofNullable;
+import static org.apache.commons.lang3.StringUtils.containsIgnoreCase;
 
 import com.google.common.collect.ImmutableMap;
 
@@ -72,9 +71,6 @@ public class AppiumDriver<T extends WebElement>
     private URL remoteAddress;
     private RemoteLocationContext locationContext;
     private ExecuteMethod executeMethod;
-    private final String platformName;
-    private final String automationName;
-
 
     /**
      * @param executor is an instance of {@link org.openqa.selenium.remote.HttpCommandExecutor}
@@ -89,20 +85,6 @@ public class AppiumDriver<T extends WebElement>
         locationContext = new RemoteLocationContext(executeMethod);
         super.setErrorHandler(errorHandler);
         this.remoteAddress = executor.getAddressOfRemoteServer();
-
-        Object capabilityPlatform1 = getCapabilities().getCapability(PLATFORM_NAME);
-        Object capabilityAutomation1 = getCapabilities().getCapability(AUTOMATION_NAME);
-
-        Object capabilityPlatform2 = capabilities.getCapability(PLATFORM_NAME);
-        Object capabilityAutomation2 = capabilities.getCapability(AUTOMATION_NAME);
-
-        platformName = ofNullable(ofNullable(super.getPlatformName())
-                .orElse(capabilityPlatform1 != null ? String.valueOf(capabilityPlatform1) : null))
-                .orElse(capabilityPlatform2 != null ? String.valueOf(capabilityPlatform2) : null);
-        automationName = ofNullable(ofNullable(super.getAutomationName())
-                .orElse(capabilityAutomation1 != null ? String.valueOf(capabilityAutomation1) : null))
-                .orElse(capabilityAutomation2 != null ? String.valueOf(capabilityAutomation2) : null);
-
         this.setElementConverter(new JsonToMobileElementConverter(this, this));
     }
 
@@ -282,15 +264,8 @@ public class AppiumDriver<T extends WebElement>
         return remoteAddress;
     }
 
-    @Override public String getPlatformName() {
-        return platformName;
-    }
-
-    @Override public String getAutomationName() {
-        return automationName;
-    }
-
     @Override public boolean isBrowser() {
-        return !getContext().toLowerCase().contains("NATIVE_APP".toLowerCase());
+        return super.isBrowser()
+                && !containsIgnoreCase(getContext(), "NATIVE_APP");
     }
 }
diff --git a/src/main/java/io/appium/java_client/HasSessionDetails.java b/src/main/java/io/appium/java_client/HasSessionDetails.java
index 3106b290..cefdfdf3 100644
--- a/src/main/java/io/appium/java_client/HasSessionDetails.java
+++ b/src/main/java/io/appium/java_client/HasSessionDetails.java
@@ -18,6 +18,7 @@ package io.appium.java_client;
 
 import static io.appium.java_client.MobileCommand.GET_SESSION;
 import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toMap;
 import static org.apache.commons.lang3.StringUtils.isBlank;
 
 import com.google.common.collect.ImmutableMap;
@@ -25,6 +26,7 @@ import com.google.common.collect.ImmutableMap;
 import org.openqa.selenium.remote.Response;
 
 import java.util.Map;
+import javax.annotation.Nullable;
 
 public interface HasSessionDetails extends ExecutesMethod {
     /**
@@ -34,26 +36,47 @@ public interface HasSessionDetails extends ExecutesMethod {
     @SuppressWarnings("unchecked")
     default Map<String, Object> getSessionDetails() {
         Response response = execute(GET_SESSION);
+        Map<String, Object> resultMap = Map.class.cast(response.getValue());
+
+        //this filtering was added to clear returned result.
+        //results of further operations should be simply interpreted by users
         return  ImmutableMap.<String, Object>builder()
-                .putAll(Map.class.cast(response.getValue())).build();
+                .putAll(resultMap.entrySet()
+                        .stream().filter(entry -> {
+                            String key = entry.getKey();
+                            Object value = entry.getValue();
+                            return !isBlank(key)
+                                && value != null
+                                && !isBlank(String.valueOf(value));
+                        }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue))).build();
     }
 
-    default Object getSessionDetail(String detail) {
+    default @Nullable Object getSessionDetail(String detail) {
         return getSessionDetails().get(detail);
     }
 
-    default String getPlatformName() {
-        Object platformName = getSessionDetail("platformName");
-        return ofNullable(platformName != null ? String.valueOf(platformName) : null).orElse(null);
+    /**
+     * @return name of the current mobile platform.
+     */
+    default @Nullable String getPlatformName() {
+        Object platformName = ofNullable(getSessionDetail("platformName"))
+                .orElseGet(() -> getSessionDetail("platform"));
+        return ofNullable(platformName).map(String::valueOf).orElse(null);
     }
 
-    default String  getAutomationName() {
-        Object automationName = getSessionDetail("automationName");
-        return ofNullable(automationName != null ? String.valueOf(automationName) : null).orElse(null);
+    /**
+     * @return current automation name.
+     */
+    default @Nullable String  getAutomationName() {
+        return ofNullable(getSessionDetail("automationName"))
+                .map(String::valueOf).orElse(null);
     }
 
     /**
      * @return is focus on browser or on native content.
      */
-    boolean isBrowser();
+    default boolean isBrowser() {
+        return ofNullable(getSessionDetail("browserName"))
+                .orElse(null) != null;
+    }
 }