Plain Java

State Design Pattern: Using Java Enums

If you want to use a Java Enum as State pattern implementation you have at least two options where to write your state transition logic. In the first case you can put it directly into your Enum source file. This is advisable for less complex and simple logic. If your logic is more complex you should use one separate class for each state.

See the following examples for both possible approaches. The class Light is used as state context. By the way, using Java Enums is a good choice if you want to store the object state as field of a JPA entity.

public class Light {

	private LightState state;

	public Light(LightState state) {
		this.state = state;
	}

	public void toggle() {
		state = state.toggle();
	}
}

All-in-one Enum approach

public enum LightState {

	OFF {
		public LightState toggle() { return ON; }
	},

	ON {
		public LightState toggle() { return OFF; }
	};

	public abstract LightState toggle();
}

Separate class for each state

// State operations interface
public interface LightStateOps {

	LightState toggle();
}

// Light Off implementation
public class LightOff implements LightStateOps {

	public LightState toggle() { return LightState.ON; }
}

// Light On implementation
public class LightOn implements LightStateOps {

	public LightState toggle() { return LightState.OFF; }
}
public enum LightState {

	OFF(new LightOff()), ON(new LightOn());

	private final LightStateOps stateOps;

	LightState(LightStateOps stateOps) {
		this.stateOps = stateOps; 
	}

	public LightState toggle() {
		return stateOps.toggle();
	}
}

Access private class fields

Sometimes during testing it can be very helpful to get access to private fields.

public class WaterCooker {

  private Heater heater;

  public boolean isHot() {
    return heater.isHot();
  }
}
@Test
public void electricHeaterAssignment() throws Exception {
  Field heaterField = waterCooker.getClass().getDeclaredField("heater");
  heaterField.setAccessible(true);
  // get old field value
  Heater oldHeater = (Heater) heaterField.get(waterCooker);
  // set new field value
  heaterField.set(waterCooker, new ElectricHeater());
  // Assert ...
}

Java Annotations and Enums

Using an enumeration type as Java annotion value makes your code type safe because it can be prechecked by your Java compiler.

@Documented
@Inherited
@Retention(RUNTIME)
@Target({ ElementType.PACKAGE })
public @interface DDDLayer {

	public enum DDDLayerType {
		USER_INTERFACE, APPLICATION_LAYER, DOMAIN_LAYER, INFRASTRUCTUR_LAYER;
	}

	DDDLayerType value();
}

Java Dynamic Return Type Cast

You can cast the return type of a method to any type by using the following statements. This can be useful if you unmarshal a serialized object.

public <T> T autoCastType(...) throws IOException {
  @SuppressWarnings("unchecked")
  T t = (T) methodThatReturnsObject(...);
  return t;
}

Ascertain Generic Superclass on Runtime

In some cases (e.g. type casting) it is necessary to know its generic superclass. The following implementation extracts that information on creation.

public abstract class Processor {

    private final Class genericType;

    public Processor() {
        genericType = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

}