Skip to content

Commit

Permalink
If the enum passed in is null, just return null too.
Browse files Browse the repository at this point in the history
  • Loading branch information
LadyCailin committed May 29, 2013
1 parent de480c6 commit 298e339
Showing 1 changed file with 65 additions and 7 deletions.
72 changes: 65 additions & 7 deletions src/main/java/com/laytonsmith/abstraction/enums/EnumConvertor.java
Expand Up @@ -7,16 +7,24 @@
import com.laytonsmith.core.constructs.Target;

/**
*
* @author Layton
* Maps an enum class to another enum class. By default, the converter uses a heuristic
* to convert the enums. The general convention is usually that enums are named the same, except
* in one off cases. If the enum isn't mapped 1:1, then the converter will need to provide the
* conversion information by overriding the get(Abstracted|Concrete)EnumCustom methods, which
* contain a switch (or similar) statement that does the proper conversion. Usually both
* or neither methods will need overriding. There is a runtime unit test, which checks
* the enums for missing values at runtime, and reports any values that can't be converted, allowing
* for easier and faster identification of failure conditions. This is not an ideal model, but
* does allow for enums themselves to be abstracted away from a particular platform.
*/
public abstract class EnumConvertor<Abstracted extends Enum, Concrete extends Enum> {

private Class<? extends Abstracted> abstractedClass;
private Class<? extends Concrete> concreteClass;

/**
* This is changed reflectively by the startup mechanism.
* This is changed reflectively by the startup mechanism. Please do not
* change the name of this variable.
*/
private boolean useError = true;
protected EnumConvertor(){
Expand All @@ -29,13 +37,32 @@ protected EnumConvertor(){
this.concreteClass = (Class<Concrete>)annotation.forConcreteEnum();
}

private static class UseDefault extends RuntimeException{ }
/**
* If the default handling should be used in the conversion, this exception can
* be thrown to signal to the parent code to perform the default heuristic
* based conversion. This is meant to be thrown from the get(Abstracted|Concrete)EnumCustom
* methods, should they be overridden.
*/
protected static class UseDefault extends RuntimeException{ }

public final Abstracted getAbstractedEnum(Concrete concrete){
/**
* Given a concrete Enum, returns the abstract version. This is generally
* called in platform specific code. The platform is given a platform specific
* enum, and it needs to return control to the abstract code, so it calls
* MyEnumConvertor.getConverter().getAbstractedEnum(PlatformSpecificEnum.VALUE),
* which in turn abstractly handles the conversion from platform to abstract enum.
* @param concrete The concrete, platform specific enum
* @return The abstract, platform independent enum
* @throws IllegalArgumentException If the enum lookup failed
*/
public final Abstracted getAbstractedEnum(Concrete concrete) throws IllegalArgumentException {
try{
try{
return getAbstractedEnumCustom(concrete);
} catch(UseDefault e){
if(concrete == null){
return null;
}
return (Abstracted)Enum.valueOf(abstractedClass, concrete.name());
}
} catch(IllegalArgumentException e){
Expand All @@ -44,15 +71,37 @@ public final Abstracted getAbstractedEnum(Concrete concrete){
}
}

protected Abstracted getAbstractedEnumCustom(Concrete concrete){
/**
* Can be overridden by subclasses that have a non 1:1 mapping. It should
* return the abstract enum, given a concrete enum. This should be used in the case
* where the heuristic isn't valid.
* @param concrete The concrete enum
* @return The abstract enum
* @throws com.laytonsmith.abstraction.enums.EnumConvertor.UseDefault If the default action
* should be taken.
*/
protected Abstracted getAbstractedEnumCustom(Concrete concrete) throws UseDefault {
throw new UseDefault();
}

/**
* Given an abstract Enum, returns the concrete version. This is generally
* called in platform specific code. The platform is given an abstract
* enum, and it needs to convert to the platform specific enum, so it calls
* MyEnumConvertor.getConverter().getConcreteEnum(AbstractEnum.VALUE),
* which in turn abstractly handles the conversion from abstract to platform enum.
* @param abstracted The abstract, platform independent enum
* @return The concrete, platform specific enum
* @throws IllegalArgumentException If the enum lookup failed
*/
public final Concrete getConcreteEnum(Abstracted abstracted){
try{
try{
return getConcreteEnumCustom(abstracted);
} catch(UseDefault e){
if(abstracted == null){
return null;
}
return (Concrete)Enum.valueOf(concreteClass, abstracted.name());
}
} catch(IllegalArgumentException e){
Expand All @@ -61,7 +110,16 @@ public final Concrete getConcreteEnum(Abstracted abstracted){
}
}

protected Concrete getConcreteEnumCustom(Abstracted abstracted){
/**
* Can be overridden by subclasses that have a non 1:1 mapping. It should
* return the concrete enum, given an abstract enum. This should be used in the case
* where the heuristic isn't valid.
* @param abstracted The abstract enum
* @return The concrete enum
* @throws com.laytonsmith.abstraction.enums.EnumConvertor.UseDefault If the default action
* should be taken.
*/
protected Concrete getConcreteEnumCustom(Abstracted abstracted) throws UseDefault {
throw new UseDefault();
}

Expand Down

0 comments on commit 298e339

Please sign in to comment.