5
\$\begingroup\$

This method is written for much larger Web application, but I just extracted it and added class and main method around it so that it can be debugged locally.

Browser detection is done in another method, then this one is called to precisely determine IE version, i.e. if it is in compatibility mode or not. All other checks are done previously.

String headerUserAgent = "headerUserAgent mozilla/5.0 (windows nt 6.1; wow64; trident/7.0; rv:11.0) like gecko"; is "REAL" IE 11 so the output will be 11.0

String headerUserAgent = "mozilla/4.0 (compatible; msie 7.0; windows nt 6.1; wow64; trident/7.0; slcc2; .net clr 2.0.50727; .net clr 3.5.30729; .net clr 3.0.30729; media center pc 6.0; .net4.0c; .net4.0e; infopath.3; gwx:reserved)"; is one of compatibility modes so output will be as expected: 00

Code works according to my tests.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UnsupportedBrowserMode
{
    public static void main(String[] args)
    {
        String headerUserAgent = "mozilla/4.0 (compatible; msie 7.0; windows nt 6.1; wow64; trident/7.0; slcc2; .net clr 2.0.50727; .net clr 3.5.30729; .net clr 3.0.30729; media center pc 6.0; .net4.0c; .net4.0e; infopath.3; gwx:reserved)";
        //String headerUserAgent = "headerUserAgent mozilla/5.0 (windows nt 6.1; wow64; trident/7.0; rv:11.0) like gecko";
        String version = getInternerExplorerVersion(headerUserAgent);
        System.out.println(version);
    }

    public static String getInternerExplorerVersion(String headerUserAgent)
    {
        String version = null;
        String TrueVersion = null;
        String ActingVersion = null;

        if (headerUserAgent != null)
        {
            headerUserAgent = headerUserAgent.toLowerCase();

            // Try to find the Trident version number
            Matcher trident = Pattern.compile("trident\\/(\\d+)").matcher(headerUserAgent);

            if (trident.find() && trident.groupCount() > 0)
            {
                // Convert from the Trident version number to the IE version number
                TrueVersion = trident.group(1);

                // If it is IE 11 TrueVersion will be overwritten with revision number
                int x = headerUserAgent.indexOf("rv:");
                if (x > 0)
                {
                  int y = headerUserAgent.indexOf(")", x);
                  if (y > x)
                  {
                      TrueVersion = headerUserAgent.substring(x + 3, y);
                  }
                }   
            }

            // Try to find the MSIE number
            Matcher msie = Pattern.compile("msie[ \\(]+([^ ;\\)]+)").matcher(headerUserAgent);
            if (msie.find() && msie.groupCount() > 0)
            {
                // Find the IE version number from the user agent string
                ActingVersion = msie.group(1);
            } else
            {
                // Must be IE 11 in "edge" mode
                ActingVersion = TrueVersion;
            }

            // If we have both a Trident and MSIE version number, see if they're different
            if (Float.parseFloat(TrueVersion) > 0 && Float.parseFloat(ActingVersion) > 0)
            {
                // In compatibility mode if the trident number doesn't match up with the MSIE number
                if (TrueVersion != ActingVersion)
                {
                    version = "00";
                } else {
                    version = TrueVersion;
                };
            }
        }

        return version;
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Shouldn't the method be called getInternetExplorerVersion \$\endgroup\$ – Heslacher Aug 5 '15 at 9:58
4
\$\begingroup\$

Returning Early

You can remove one level of nesting, and make your code generally easier to understand by returning early:

if (headerUserAgent == null) {
    return null;
}

Now it's also more obvious what happens if the agent is null. But is returning null really what you want? It will lead to a lot of if (agent == null) in the calling code. I would suggest throwing an exception instead. Java also has a nice utility method for this:

Objects.requireNonNull(headerUserAgent, "User Agent is Null");

(This method should be used if the agent being null is not expected. If you do expect it, because it's part of your program logic, this might not be the best approach)

Bugs

Your code doesn't work for quite a lot of input:

  • empty string, , ua, etc as input results in a NullPointerException.
  • Some Firefox user agents also result in NullPointerException, eg Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0.
  • You can see a list of some possible IE user agents here. I tried some of them, and a lot result in exceptions, such as Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US)), which should be IE 9, Mozilla/5.0 (MSIE 7.0; Macintosh; U; SunOS; X11; gu; SV1; InfoPath.2; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648) which should be IE 7, or Mozilla/1.22 (compatible; MSIE 10.0; Windows 3.1) which should be IE 10 (or 00 in your case).

Misc

  • Your placement of the { is not really following Java conventions.
  • Some of your variable names could be more descriptive, eg x and y.
  • Variables should start with a lower-case character.
  • You have an unnecessary ;.
  • A JavaDoc style comment describing the exact return values might be a good idea, especially since the method name is a bit confusing (it doesn't always return the version, but 00 for compatibility mode).
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ UPDATE: Browser detection is done in another method, then this one is called to precisely determine IE version. {} convention is not chosen by me but by authors of whole Web application. \$\endgroup\$ – Nenad Bulatovic Aug 5 '15 at 10:42
  • 1
    \$\begingroup\$ @NenadBulatovic Still, I think your method shouldn't cause unexpected exceptions. It's not good in general and hurts reusability. Also, the list of user agents I linked to only contains IE agents, and a lot of them don't seem to work either. \$\endgroup\$ – tim Aug 5 '15 at 10:47
  • \$\begingroup\$ I agree abut variable names, I rewrote JavaScript for detection of IE. Should rename them but I overlooked, thanks for pointing it. As for input strings they are carefully filtered prior to this method so no real possibility to got an exception. Adding additional check would be repeat. Where do you see unnecessary ; ? \$\endgroup\$ – Nenad Bulatovic Aug 5 '15 at 10:51
  • \$\begingroup\$ String headerUserAgent = "headerUserAgent mozilla/5.0 (windows nt 6.1; wow64; trident/7.0; rv:11.0) like gecko"; is "REAL" IE 11 so the output will be 11.0 \$\endgroup\$ – Nenad Bulatovic Aug 5 '15 at 10:53
  • 1
    \$\begingroup\$ @NenadBulatovic Oh, ok. You should probably add a JavaDoc comment, describing the expected return values. Still, some UAs cause errors. Eg Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US)), which is IE 9 according to the link results in an exception, so does Mozilla/5.0 (MSIE 7.0; Macintosh; U; SunOS; X11; gu; SV1; InfoPath.2; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648) which should be IE 7, or Mozilla/1.22 (compatible; MSIE 10.0; Windows 3.1) which should be IE 10 (or 00 in your case). \$\endgroup\$ – tim Aug 5 '15 at 10:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.