98

I have an enum switch more or less like this:

public static enum MyEnum {A, B}

public int foo(MyEnum value) {
    switch(value) {
        case(A): return calculateSomething();
        case(B): return calculateSomethingElse();
    }
    throw new IllegalArgumentException("Do not know how to handle " + value);
}

and I'd like to have all the lines covered by the tests, but as the code is expected to deal with all possibilities, I cannot supply a value without its corresponding case statement in the switch.

Extending the enum to add an extra value is not possible, and just mocking the equals method to return false won't work either because the bytecode generated uses a jump table behind the curtains to go to the proper case... So I've thought that maybe some black magic could be achieved with PowerMock or something.

Thanks!

edit:

As I own the enumeration, I've thought that I could just add a method to the values and thus avoid the switch issue completely; but I'm leaving the question as it's still interesting.

fortran
  • 74,053
  • 25
  • 135
  • 175
  • 1
    An IlegalArgument that can never be thrown because of the clear properties of the enum, yet you what to bastardise your code to test that it will handle the impossible? If you really want to fetishise your line civerage metric, why not just delete the line that can never be executed? – Raedwald Aug 22 '13 at 22:27
  • 16
    @Raedwald 2 reasons: first, somebody else might create a new value for the enum and forget to add a new case for the switch; second, the code won't compile without a `throw` or `return` after the switch. – fortran Aug 23 '13 at 10:17
  • 1
    After consideration, I think just leave it untested. There isn't an illegal enum value to trigger the Exception and it's painful to mock. I think the throw is good, it's future proof, just really hard to test. Not worth the effort testing, IMHO. – Robert Bain Sep 20 '16 at 21:51
  • @Melloware > ... code that executes the switch() statement java throws a java.lang.ArrayIndexOutOfBounds ... I have this same Problem. Run your test with new Enum as first in your Test Class. I created bug with this Problem: https://code.google.com/p/powermock/issues/detail?id=440 – Marcin Stachniuk May 22 '13 at 22:44
  • It works better when I use @PrepareForTest(MyEnum.class) at Method level. – Marcin Stachniuk May 22 '13 at 23:38
  • really, you should not use `switch` on `enum` ... the `calculate*()` methods should be defined (possibly as a lamba, or abstract/override) on the `enum MyEnum` instead. your `foo()` method wlil disappear, alongside with the `throw new IllegalArgumentException`. When adding a new entry in the `enum`, you zwill be forced to defined it with its own `calclute()` behavior – Julien Feb 27 '20 at 13:40

11 Answers11

71

Here is a complete example.

The code is almost like your original (just simplified better test validation):

public enum MyEnum {A, B}

public class Bar {

    public int foo(MyEnum value) {
        switch (value) {
            case A: return 1;
            case B: return 2;
        }
        throw new IllegalArgumentException("Do not know how to handle " + value);
    }
}

And here is the unit test with full code coverage, the test works with Powermock (1.4.10), Mockito (1.8.5) and JUnit (4.8.2):

@RunWith(PowerMockRunner.class)
public class BarTest {

    private Bar bar;

    @Before
    public void createBar() {
        bar = new Bar();
    }

    @Test(expected = IllegalArgumentException.class)
    @PrepareForTest(MyEnum.class)
    public void unknownValueShouldThrowException() throws Exception {
        MyEnum C = mock(MyEnum.class);
        when(C.ordinal()).thenReturn(2);

        PowerMockito.mockStatic(MyEnum.class);
        PowerMockito.when(MyEnum.values()).thenReturn(new MyEnum[]{MyEnum.A, MyEnum.B, C});

        bar.foo(C);
    }

    @Test
    public void AShouldReturn1() {
        assertEquals(1, bar.foo(MyEnum.A));
    }

    @Test
    public void BShouldReturn2() {
        assertEquals(2, bar.foo(MyEnum.B));
    }
}

Result:

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.628 sec
Slava Shpitalny
  • 3,965
  • 2
  • 15
  • 22
Jonny Heggheim
  • 1,423
  • 1
  • 12
  • 19
  • 6
    I followed your example using Mockito 1.9.0 and PowerMock 1.4.12 and I was able to inject a new enum into my list however in the code that executes the switch() statement java throws a java.lang.ArrayIndexOutOfBounds exception like it knows there is not supposed to be an extra one. Any thoughts? – Melloware Jul 20 '12 at 22:01
  • 4
    In case someone runs into the problem @Melloware had, the following might be useful. To get the above example to work in my own tests, I had to add ALL values of the original Enum, AND the mocked one in the when/thenReturn statement, and set the ordinal correctly. If you mock one value extra, the ordinal should be the number of values in your original unmocked Enum. – JeroenHoek Oct 04 '13 at 21:23
  • 3
    How can you PowerMockito.mockStatic(MyEnum.class);? It should give java.lang.IllegalArgumentException: Cannot subclass final class – Thamiar Nov 20 '15 at 08:59
  • At least with normal Mockito it throws the exception. – borjab Apr 11 '16 at 16:58
  • When you use the JUnit Rule annotations like in this answer [link](http://stackoverflow.com/questions/2469911/how-do-i-assert-my-exception-message-with-junit-test-annotation) and check if the exception message is actually the one you wanted you should see not your intended Exception is thrown. Therefore I think this answer is wrong. Or something in PowerMock or so changed since this answer was given ... – giro Aug 18 '16 at 10:27
  • Works just fine. Powermock:1.6.5, Mockito:2.0.42-beta, JUnit:4.12 – Veaceslav Gaidarji Aug 25 '16 at 09:47
  • Really works fine. Don't know what I did wrong back in august. Powermock 1.6.5, Mockito 2.0.2-beta, JUnit 4.12 – giro Nov 01 '16 at 19:58
  • 1
    Excellent! I but I improved a bit the solution. At `Whitebox.setInternalState(C, "ordinal", 2);` it is possible to pass `foo` instead of `2`. And initialize `foo` as `int foo = MyEnum.values().length;` as a first string (above `MyEnum C = PowerMockito.mock(MyEnum.class);`) – Alexander Skvortsov Dec 25 '16 at 20:28
  • Grate solution! Pls be noticed that mocked enum you were unable to use with EnumMap and will get IndexOutOfBoundException. Its related to using of native methods while the EnumMap is constracted, so keys for map will get only original ones. – Mykola Tychyna Feb 14 '19 at 07:56
  • In my case it worked when I switched the `Whitebox` lines with regular mocking of the `ordinal()` method – Slava Shpitalny Feb 20 '20 at 14:10
  • I tried both PowerMockito.when..thenReturn as well as whitebox. For me, MyEnum has a method called baz(), that throws exception for unknown enum value. After whitebox ordinal is returning 2 but still C.baz() is returning null instead of exception. Any idea what could cause this? – Kiran A B Jun 05 '20 at 18:33
  • To whom struggling with java.lang.ArrayIndexOutOfBounds exception; This is the solution what I've done to solve this: move all the mocking and WhenThen logic for MyEnum into the method annotated with @Before. – Taner Jun 13 '20 at 12:06
  • in my code after setting `when(C.ordinal()).thenReturn(2);` it always return `0`, for this use `Whitebox.setInternalState(c, "ordinal", 6);` and also add all the remaining enum values also – namila007 Nov 03 '20 at 11:48
25

If you can use Maven as your build system, you can use a much simpler approach. Just define the same enum with an additional constant in your test classpath.

Let's say you have your enum declared under the sources directory (src/main/java) like this:

package my.package;

public enum MyEnum {
    A,
    B
}

Now you declare the exact same enum in the test sources directory (src/test/java) like this:

package my.package

public enum MyEnum {
    A,
    B,
    C
}

The tests see the testclass path with the "overloaded" enum and you can test your code with the "C" enum constant. You should see your IllegalArgumentException then.

Tested under windows with maven 3.5.2, AdoptOpenJDK 11.0.3 and IntelliJ IDEA 2019.3.1

Frank S.
  • 400
  • 3
  • 3
  • 3
    This is a pretty elegant solution! I don't know how I could miss it completely back then it only worries me that relying on classpath precedence rules when there's a repeated class definition could be flimsy – fortran Jan 23 '20 at 14:46
  • I'm not seeing this work with gradle. I think using PowerMockito in the answer here seems like a better "general" answer: https://stackoverflow.com/questions/5323505/mocking-java-enum-to-add-a-value-to-test-fail-case#answer-7233572 – Bret Royster Jul 29 '20 at 13:59
  • 1
    eclipse seems to reject this solution `The type MyEnum is already defined` – wutzebaer Nov 21 '20 at 11:26
  • IntelliJ IDEA 2020.2.3 (Ultimate Edition) Build #IU-202.7660.26, built on October 6, 2020 - shows C as "Cannot Resolve symbol C" - however mvn install and tests run just fine :) Probably a bug to report to IntelliJ – MadaManu Jan 15 '21 at 12:36
  • Worked fine with Gradle for me (IntelliJ IDEA 2021.2) – Boommeister Dec 15 '21 at 08:49
  • Could this solution be somehow applied to an enum defined inside a class? For example: `a.package.i.dont.own.AClass.AnEnum` I would like to redefine the enum in my test, but I don't want to redefine the AClass class. – Christophe Broeckx Nov 17 '22 at 06:09
  • It works, but code coverage missing in actual package enum class. – Saravanan Jun 26 '23 at 10:21
8

Here is my Mockito only version of the solution of @Jonny Heggheim. It has been tested with Mockito 3.9.0 and Java 11:

public class MyTestClass {

  private static MockedStatic<MyEnum> myMockedEnum;
  private static MyEnum mockedValue;

  @BeforeClass
  public void setUp() {
    MyEnum[] newEnumValues = addNewEnumValue(MyEnum.class);
    myMockedEnum = mockStatic(MyEnum.class);
    myMockedEnum.when(MyEnum::values).thenReturn(newEnumValues);
    mockedValue = newEnumValues[newEnumValues.length - 1];
  }
 
  @AfterClass
  public void tearDown(){
    myMockedEnum.close();
  }

  @Test
  public void testCase(){
    // Use mockedValue in your test case
    ...
  }

  private static <E extends Enum<E>> E[] addNewEnumValue(Class<E> enumClazz){
    EnumSet<E> enumSet = EnumSet.allOf(enumClazz);
    E[] newValues = (E[]) Array.newInstance(enumClazz, enumSet.size() + 1);
    int i = 0;
    for (E value : enumSet) {
      newValues[i] = value;
      i++;
    }

    E newEnumValue = mock(enumClazz);
    newValues[newValues.length - 1] = newEnumValue;

    when(newEnumValue.ordinal()).thenReturn(newValues.length - 1);

    return newValues;
  }
}

A few words of caution when using this:

  • It is crucial that you run the code in the setup() Method before any class is loaded by the JVM classloader that contains a switch statement for the mocked Enum. I recommend you read the article quoted in the answer of @Vampire if you want to know why.
  • The safest way to achieve this is to put the code in a static method annotated with @BeforeClass.
  • If you forget the code in the tearDown() method if can happen that the tests in the test class succeed but tests in other test classes fail when run afterwards in the same test run. This is because MyEnum stays extended until you call close() on MockedStatic.
  • If in the same test class some of your test cases use the mocked Enum and some don't and you have to pull the setUp() and tearDown() code into single test cases, I highly recommend running the tests with the Robolectric runner or any other test runner, that guarantees that each test case runs in a freshly started JVM. This way you can make sure, that all classes that contain switch statements for the Enum are newly loaded by the class loader for every test case.
Nantoka
  • 4,174
  • 1
  • 33
  • 36
  • That is a really god option for a only mockito solution. Thanks! – taciosd May 31 '22 at 17:38
  • At line `E newEnumValue = mock(enumClazz);`, which `mock` are you using? Because Mockito-4+ version is telling me that can't mock my enum as consider it `final`. – lucasvc Oct 21 '22 at 15:59
  • I use the static Mockito::mock method. We are still using Mockito 3.9.0 and there this problem does not exist. Could be that I have to rewrite something once we upgrade to the newest Mockito version. Thanks for the warning. :) – Nantoka Oct 25 '22 at 23:39
3

Just creating a fake enum value will not be enough, you eventually also need to manipulate an integer array that is created by the compiler.


Actually to create a fake enum value, you don't even need any mocking framework. You can just use Objenesis to create a new instance of the enum class (yes, this works) and then use plain old Java reflection to set the private fields name and ordinal and you already have your new enum instance.

Using Spock framework for testing, this would look something like:

given:
    def getPrivateFinalFieldForSetting = { clazz, fieldName ->
        def result = clazz.getDeclaredField(fieldName)
        result.accessible = true
        def modifiers = Field.getDeclaredFields0(false).find { it.name == 'modifiers' }
        modifiers.accessible = true
        modifiers.setInt(result, result.modifiers & ~FINAL)
        result
    }

and:
    def originalEnumValues = MyEnum.values()
    MyEnum NON_EXISTENT = ObjenesisHelper.newInstance(MyEnumy)
    getPrivateFinalFieldForSetting.curry(Enum).with {
        it('name').set(NON_EXISTENT, "NON_EXISTENT")
        it('ordinal').setInt(NON_EXISTENT, originalEnumValues.size())
    }

If you also want the MyEnum.values() method to return the new enum, you now can either use JMockit to mock the values() call like

new MockUp<MyEnum>() {
    @Mock
    MyEnum[] values() {
        [*originalEnumValues, NON_EXISTENT] as MyEnum[]
    }
}

or you can again use plain old reflection to manipulate the $VALUES field like:

given:
    getPrivateFinalFieldForSetting.curry(MyEnum).with {
        it('$VALUES').set(null, [*originalEnumValues, NON_EXISTENT] as MyEnum[])
    }

expect:
    true // your test here

cleanup:
    getPrivateFinalFieldForSetting.curry(MyEnum).with {
        it('$VALUES').set(null, originalEnumValues)
    }

As long as you don't deal with a switch expression, but with some ifs or similar, either just the first part or the first and second part might be enough for you.

If you however are dealing with a switch expression, e. g. wanting 100% coverage for the default case that throws an exception in case the enum gets extended like in your example, things get a bit more complicated and at the same time a bit more easy.

A bit more complicated because you need to do some serious reflection to manipulate a synthetic field that the compiler generates in a synthetic anonymous innner class that the compiler generates, so it is not really obvious what you are doing and you are bound to the actual implementation of the compiler, so this could break anytime in any Java version or even if you use different compilers for the same Java version. It is actually already different between Java 6 and Java 8.

A bit more easy, because you can forget the first two parts of this answer, because you don't need to create a new enum instance at all, you just need to manipulate an int[], that you need to manipulate anyway to make the test you want.

I recently found a very good article regarding this at https://www.javaspecialists.eu/archive/Issue161.html.

Most of the information there is still valid, except that now the inner class containing the switch map is no longer a named inner class, but an anonymous class, so you cannot use getDeclaredClasses anymore but need to use a different approach shown below.

Basically summarized, switch on bytecode level does not work with enums, but only with integers. So what the compiler does is, it creates an anonymous inner class (previously a named inner class as per the article writing, this is Java 6 vs. Java 8) that holds one static final int[] field called $SwitchMap$net$kautler$MyEnum that is filled with integers 1, 2, 3, ... at the indices of MyEnum#ordinal() values.

This means when the code comes to the actual switch, it does

switch(<anonymous class here>.$SwitchMap$net$kautler$MyEnum[myEnumVariable.ordinal()]) {
    case 1: break;
    case 2: break;
    default: throw new AssertionError("Missing switch case for: " + myEnumVariable);
}

If now myEnumVariable would have the value NON_EXISTENT created in the first step above, you would either get an ArrayIndexOutOfBoundsException if you set ordinal to some value greater than the array the compiler generated, or you would get one of the other switch-case values if not, in both cases this would not help to test the wanted default case.

You could now get this int[] field and fix it up to contain a mapping for the orinal of your NON_EXISTENT enum instance. But as I said earlier, for exactly this use-case, testing the default case, you don't need the first two steps at all. Instead you can simple give any of the existing enum instances to the code under test and simply manipulate the mapping int[], so that the default case is triggered.

So all that is necessary for this test case is actually this, again written in Spock (Groovy) code, but you can easily adapt it to Java too:

given:
    def getPrivateFinalFieldForSetting = { clazz, fieldName ->
        def result = clazz.getDeclaredField(fieldName)
        result.accessible = true
        def modifiers = Field.getDeclaredFields0(false).find { it.name == 'modifiers' }
        modifiers.accessible = true
        modifiers.setInt(result, result.modifiers & ~FINAL)
        result
    }

and:
    def switchMapField
    def originalSwitchMap
    def namePrefix = ClassThatContainsTheSwitchExpression.name
    def classLoader = ClassThatContainsTheSwitchExpression.classLoader
    for (int i = 1; ; i++) {
        def clazz = classLoader.loadClass("$namePrefix\$$i")
        try {
            switchMapField = getPrivateFinalFieldForSetting(clazz, '$SwitchMap$net$kautler$MyEnum')
            if (switchMapField) {
                originalSwitchMap = switchMapField.get(null)
                def switchMap = new int[originalSwitchMap.size()]
                Arrays.fill(switchMap, Integer.MAX_VALUE)
                switchMapField.set(null, switchMap)
                break
            }
        } catch (NoSuchFieldException ignore) {
            // try next class
        }
    }

when:
    testee.triggerSwitchExpression()

then:
    AssertionError ae = thrown()
    ae.message == "Unhandled switch case for enum value 'MY_ENUM_VALUE'"

cleanup:
    switchMapField.set(null, originalSwitchMap)

In this case you don't need any mocking framework at all. Actually it would not help you anyway, as no mocking framework I'm aware of allows you to mock an array access. You could use JMockit or any mocking framework to mock the return value of ordinal(), but that would again simply result in a different switch-branch or an AIOOBE.

What this code I just shown does is:

  • it loops through the anonymous classes inside the class that contains the switch expression
  • in those it searches for the field with the switch map
  • if the field is not found, the next class is tried
  • if a ClassNotFoundException is thrown by Class.forName, the test fails, which is intended, because that means that you compiled the code with a compiler that follows a different strategy or naming pattern, so you need to add some more intelligence to cover different compiler strategies for switching on enum values. Because if the class with the field is found, the break leaves the for-loop and the test can continue. This whole strategy of course depends on anonymous classes being numbered starting from 1 and without gaps, but I hope this is a pretty safe assumption. If you are dealing with a compiler where this is not the case, the searching algorithm needs to be adapted accordingly.
  • if the switch map field is found, a new int array of the same size is created
  • the new array is filled with Integer.MAX_VALUE which usually should trigger the default case as long as you don't have an enum with 2,147,483,647 values
  • the new array is assigned to the switch map field
  • the for loop is left using break
  • now the actual test can be done, triggering the switch expression to be evaluated
  • finally (in a finally block if you are not using Spock, in a cleanup block if you are using Spock) to make sure this does not affect other tests on the same class, the original switch map is put back into the switch map field
Vampire
  • 35,631
  • 4
  • 76
  • 102
  • Thanks a lot for the link to the javaspecialists article. With this article I finally understood where the problems of my Mockito - based solution were and could finally fix them. – Nantoka May 12 '21 at 23:20
2

jMock (at least as of version 2.5.1 that I'm using) can do this out of the box. You will need to set your Mockery to use ClassImposterizer.

Mockery mockery = new Mockery();
mockery.setImposterizer(ClassImposterizer.INSTANCE);
MyEnum unexpectedValue = mockery.mock(MyEnum.class);
Kevin Peterson
  • 7,189
  • 5
  • 36
  • 43
2

Rather than using some radical bytecode manipulation to enable a test to hit the last line in foo, I would remove it and rely on static code analysis instead. For example, IntelliJ IDEA has the "Enum switch statement that misses case" code inspection, which would produce a warning for the foo method if it lacked a case.

Rogério
  • 16,171
  • 2
  • 50
  • 63
  • 1
    That's why I put the fail action outside a "default" case, to allow static analysis too... But I'm not willing to remove a runtime check and just rely on static analysis, I think both should be complementary. – fortran Mar 18 '11 at 11:20
  • That was my point, to use static analysis to complement a test suite + code coverage. If you use it, then the line with the `throw` statement becomes redundant and can be removed, since the lack of a `case` in the `switch` would be detected by the IDE/build. – Rogério Mar 18 '11 at 13:19
  • I think this is a good idea. The default case for an enum isn't really code in the sense that its part of the application that is ever run, its code to future proof it against something you might do that might introduce a bug down the line. Better to just code your application, and ensure it is correct. Is there an "enum switch statement that misses case" rule for Sonar? – user2800708 Nov 20 '15 at 09:08
2

As you indicated in your edit, you can add the functionaliy in the enum itself. However, this might not be the best option, since it can violate the "One Responsibility" principle. Another way to achieve this is to create a static map which contains enum values as key and the functionality as value. This way, you can easily test if for any enum value you have a valid behavior by looping over all the values. It might be a bit far fetched on this example, but this is a technique I use often to map resource ids to enum values.

bert bruynooghe
  • 2,985
  • 1
  • 20
  • 18
  • 1
    This doesn't help, especially if you don't have the enum under your control. A consumer then could use a newer version of the enum that has more values and a test that checks that a proper exception is thrown or default action is done might pretty much make sense. – Vampire Sep 06 '19 at 16:25
0

First of all Mockito can create mock data which can be integer long etc It cannot create right enum as enum has specific number of ordinal name value etc so if i have an enum

public enum HttpMethod {
      GET, POST, PUT, DELETE, HEAD, PATCH;
}

so i have total 5 ordinal in enum HttpMethod but mockito does not know it .Mockito creates mock data and its null all the time and you will end up in passing a null value . So here is proposed solution that you randomize the ordinal and get a right enum which can be passed for other test

import static org.mockito.Mockito.mock;

import java.util.Random;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.internal.util.reflection.Whitebox;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.amazonaws.HttpMethod;




//@Test(expected = {"LoadableBuilderTestGroup"})
//@RunWith(PowerMockRunner.class)
public class testjava {
   // private static final Class HttpMethod.getClass() = null;
    private HttpMethod mockEnumerable;

    @Test
    public void setUpallpossible_value_of_enum () {
        for ( int i=0 ;i<10;i++){
            String name;
            mockEnumerable=    Matchers.any(HttpMethod.class);
            if(mockEnumerable!= null){
                System.out.println(mockEnumerable.ordinal());
                System.out.println(mockEnumerable.name());

                System.out.println(mockEnumerable.name()+"mocking suceess");
            }
            else {
                //Randomize all possible  value of  enum 
                Random rand = new Random();
                int ordinal = rand.nextInt(HttpMethod.values().length); 
                // 0-9. mockEnumerable=
                mockEnumerable= HttpMethod.values()[ordinal];
                System.out.println(mockEnumerable.ordinal());
                System.out.println(mockEnumerable.name());
            }
        }
    }







    @Test
    public void setUpallpossible_value_of_enumwithintany () {
        for ( int i=0 ;i<10;i++){
            String name;
            mockEnumerable=    Matchers.any(HttpMethod.class);
            if(mockEnumerable!= null){
                System.out.println(mockEnumerable.ordinal());
                System.out.println(mockEnumerable.name());

                System.out.println(mockEnumerable.name()+"mocking suceess");
            } else {
               int ordinal;
               //Randomize all possible  value of  enum 
               Random rand = new Random();
               int imatch =  Matchers.anyInt();
               if(  imatch>HttpMethod.values().length)
                 ordinal = 0    ;
               else
                ordinal = rand.nextInt(HttpMethod.values().length);

               // 0-9.  mockEnumerable=
               mockEnumerable= HttpMethod.values()[ordinal];
               System.out.println(mockEnumerable.ordinal());
               System.out.println(mockEnumerable.name());       
            }
       }  
    }
}

Output :

0
GET
0
GET
5
PATCH
5
PATCH
4
HEAD
5
PATCH
3
DELETE
0
GET
4
HEAD
2
PUT
Basit Anwer
  • 6,742
  • 7
  • 45
  • 88
Jin Thakur
  • 2,711
  • 18
  • 15
0

I think that the simplest way to reach the IllegalArgumentException is to pass null to the foo method and you will read "Do not know how to handle null"

  • 5
    This is not helpful at all, because `switch`ing on a `null` value will yields a `NullPointerException` and not follow the `default` case (which in the example falls through to after the `switch` statement. – Vampire Sep 05 '19 at 13:52
0

I added an Unknown option to my enum, which I pass in during the test. Not ideal in every case, but simple.

Ryan
  • 550
  • 4
  • 9
-11

I would put the default case with one of enum cases:

  public static enum MyEnum {A, B}

  public int foo(MyEnum value) {
    if (value == null) throw new IllegalArgumentException("Do not know how to handle " + value);

    switch(value) {
        case(A):
           return calculateSomething();
        case(B):
        default:
           return calculateSomethingElse();
    }
  }
eliocs
  • 18,511
  • 7
  • 40
  • 52
  • 16
    This is not the desired behaviour, it will produce unexpected results when a new enumeration value is added. – fortran Mar 16 '11 at 10:40