Thomas Auinger
Thomas Auinger

Reputation: 2095

Weird behaviour with db4o after refactoring enum

We have refactored an enum used in our model to include new values. Now when the application executes (using a database file created by the old application), some switch/case statements behave very strangely.

The debug variables view shows that, e.g. the enum has value "OLD", but the debugger steps into the "case NEW:" line.

Any thoughts? Cheers!

Update:

The following code

ObjectSet<Project> set = db.query(Project.class);
System.out.println("Found " + set.size());
for (Project prj : set) {
    // this line makes no difference
    ProjectStatus otherStatus = ProjectStatus.valueOf(prj.getStatus().name());

    // debug
    System.out.println(otherStatus.name());

    // decide via switch/case
    switch (otherStatus) {
        case A:
            System.out.println("Project status is A (switch/case)");
            break;
        case B:
            System.out.println("Project status is B (switch/case)");
            break;
    }

    // decide via if
    if (otherStatus == ProjectStatus.A) {
        System.out.println("Project status is A (if ==)");
    }
    else if (otherStatus == ProjectStatus.B) {
        System.out.println("Project status is B (if ==)");
    }
}

produces output

Found 1
B
Project status is B (if ==)

We tried db4o 6.4 and 7.12

Also, depending on the type of enum refactoring, if we remove enum values, the following exception is thrown:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
    at Main.$SWITCH_TABLE$model$ProjectStatus(Main.java:8)
    at Main.main(Main.java:37)

Upvotes: 0

Views: 410

Answers (1)

Gamlor
Gamlor

Reputation: 13258

So I could observe this behavior:

We have an enum like this:

public enum SomeState { 
 One, 
 Two 
} 

and a switch statement on this:

switch(object.getState()){ 
 case One: doSomething("State One");break; 
 case Two: doSomething("State Two");break; 
} 

We've stored a object with the state Two, so it will 'switch' to the second case.

Now we refactor the enum. We rename the second value and add a new one:

public enum SomeState { 
 One, 
 NewTwo, 
 OldTwo 
} 

And the new switch-statement:

switch(object.getState()){ 
 case One: doSomething("State One");break; 
 case NewTwo: doSomething("State New Two");break; 
 case OldTwo: doSomething("State Old Two");break; 
} 

Now that object will 'switch' to the 'NewTwo' state, which is completely wrong!

Unfortunately is a bug: I've added a entry here (http://tracker.db4o.com/browse/COR-2268). The underlying issue is that strange enum-handling of db4o. It actually stores the enum object itself. When loading the object from the database it restores the enum-state, even the stuff in static variables! If meanwhile the refactoring has taken place the whole stuff is messed up. Basically we multiple enums with the same ordinals and messed up names.

For now I would recommend to avoid enums (on Java. In .Net the db4o enum handling works) =(.

Edit: Suggestion for the migration: You could do this: Add the 'refactored' enums as complete new values to the enum. Then load all objects containing that enum and change the values to the new values. After that you then remove the old enum-values.

Upvotes: 2

Related Questions