java - Subclassing ENUMs -


this question has answer here:

the approach quite simple. want subclass enum b b inherits values of a.

i'm aware post can enums subclassed add new elements? describes various solutions (including mine). don't think last post read after answers. made fresh post answer in hopes solutions seen , maybe used.

i'd share elegant approach of colleague subclassing follows interface approach , beyond.

please aware use custom exceptions here , code won't compile unless replace exceptions.

the documentation extensive , hope it's understandable of you.

the interface every subclassed enum needs implement.

public interface parameter {   /**    * retrieve parameters name.    *    * @return name of parameter    */   string getname();    /**    * retrieve parameters type.    *    * @return {@link class} according type of parameter    */   class<?> gettype();    /**    * matches given string parameters value pattern (if applicable). helps find    * out if given string syntactically valid candidate parameters value.    *    * @param valuestr <i>optional</i> - string check    * @return <code>true</code> in case parameter has no pattern defined or given string    *         matches defined one, <code>false</code> in case <code>valuestr</code>    *         <code>null</code> or existing pattern not matched    */   boolean match(final string valuestr);    /**    * method works {@link #match(string)} throws exception if not matched.    *    * @param valuestr <i>optional</i> - string check    * @throws argumentexception code    *           <dl>    *           <dt>param_missed</dt>    *           <dd>if <code>valuestr</code> <code>null</code></dd>    *           <dt>param_bad</dt>    *           <dd>if pattern not matched</dd>    *           </dl>    */   void matchex(final string valuestr) throws argumentexception;    /**    * parses value parameter given string. method honors parameters data    * type , potentially other criteria defining valid value (e.g. pattern).    *    * @param valuestr <i>optional</i> - string parse parameter value    * @return parameter value according parameters type (see {@link #gettype()}) or    *         <code>null</code> in case <code>valuestr</code> <code>null</code>.    * @throws argumentexception in case <code>valuestr</code> not parsable value    *           parameter.    */   object parse(final string valuestr) throws argumentexception;    /**    * converts given value external form accepted {@link #parse(string)}.    * (ordinary) parameters call {@link string#valueof(object)}. in case    * parameter types {@link object#tostring()} method not return external form (e.g.    * enumerations), method has implemented accordingly.    *    * @param value <i>mandatory</i> - parameters value    * @return external form of parameters value, never <code>null</code>    * @throws internalserviceexception in case given <code>value</code> not match    *           {@link #gettype()}    */   string tostring(final object value) throws internalserviceexception; } 

the implementing enum base class.

public enum parameters implements parameter {   /**    * enum value    */   value(new parameterimpl<string>("value", string.class, "[a-za-z]{3,10}"));    /**    * parameter wrapped enum constant.    */   private parameter param;    /**    * constructor.    *    * @param param <i>mandatory</i> - value {@link #param}    */   private parameters(final parameter param) {     this.param = param;   }    /**    * {@inheritdoc}    */   @override   public string getname() {     return this.param.getname();   }    /**    * {@inheritdoc}    */   @override   public class<?> gettype() {     return this.param.gettype();   }    /**    * {@inheritdoc}    */   @override   public boolean match(final string valuestr) {     return this.param.match(valuestr);   }    /**    * {@inheritdoc}    */   @override   public void matchex(final string valuestr) {     this.param.matchex(valuestr);   }    /**    * {@inheritdoc}    */   @override   public object parse(final string valuestr) throws argumentexception {     return this.param.parse(valuestr);   }    /**    * {@inheritdoc}    */   @override   public string tostring(final object value) throws internalserviceexception {     return this.param.tostring(value);   } } 

the subclassed enum "inherits" base class.

public enum extendedparameters implements parameter {   /**    * enum value    */   value(my.package.name.value);    /**    * extended enum value    */   extended_value(new parameterimpl<string>("extended_value", string.class, "[0-9a-za-z_.-]{1,20}"));    /**    * parameter wrapped enum constant.    */   private parameter param;    /**    * constructor.    *    * @param param <i>mandatory</i> - value {@link #param}    */   private parameters(final parameter param) {     this.param = param;   }    /**    * {@inheritdoc}    */   @override   public string getname() {     return this.param.getname();   }    /**    * {@inheritdoc}    */   @override   public class<?> gettype() {     return this.param.gettype();   }    /**    * {@inheritdoc}    */   @override   public boolean match(final string valuestr) {     return this.param.match(valuestr);   }    /**    * {@inheritdoc}    */   @override   public void matchex(final string valuestr) {     this.param.matchex(valuestr);   }    /**    * {@inheritdoc}    */   @override   public object parse(final string valuestr) throws argumentexception {     return this.param.parse(valuestr);   }    /**    * {@inheritdoc}    */   @override   public string tostring(final object value) throws internalserviceexception {     return this.param.tostring(value);   } } 

finally generic parameterimpl add utilities.

public class parameterimpl<t> implements parameter {   /**    * default pattern numeric (integer, long) parameters.    */   private static final pattern number_pattern = pattern.compile("[0-9]+");    /**    * default pattern parameters of type boolean.    */   private static final pattern boolean_pattern = pattern.compile("0|1|true|false");    /**    * name of parameter, never <code>null</code>.    */   private final string name;    /**    * data type of parameter.    */   private final class<t> type;    /**    * validation pattern parameters values. may <code>null</code>.    */   private final pattern validator;    /**    * shortcut constructor without <code>validatorpattern</code>.    *    * @param name <i>mandatory</i> - value {@link #name}    * @param type <i>mandatory</i> - value {@link #type}    */   public parameterimpl(final string name, final class<t> type) {     this(name, type, null);   }    /**    * constructor.    *    * @param name <i>mandatory</i> - value {@link #name}    * @param type <i>mandatory</i> - value {@link #type}    * @param validatorpattern - <i>optional</i> - pattern {@link #validator}    *          <dl>    *          <dt style="margin-top:0.25cm;"><i>note:</i>    *          <dd>the default validation patterns {@link #number_pattern} or    *          {@link #boolean_pattern} applied accordingly.    *          </dl>    */   public parameterimpl(final string name, final class<t> type, final string validatorpattern) {     this.name = name;     this.type = type;     if (null != validatorpattern) {       this.validator = pattern.compile(validatorpattern);      } else if (integer.class == this.type || long.class == this.type) {       this.validator = number_pattern;     } else if (boolean.class == this.type) {       this.validator = boolean_pattern;     } else {       this.validator = null;     }   }    /**    * {@inheritdoc}    */   @override   public boolean match(final string valuestr) {     if (null == valuestr) {       return false;     }     if (null != this.validator) {       final matcher matcher = this.validator.matcher(valuestr);       return matcher.matches();     }     return true;   }    /**    * {@inheritdoc}    */   @override   public void matchex(final string valuestr) throws argumentexception {     if (false == this.match(valuestr)) {       if (null == valuestr) {         throw argumentexception.createex(errorcode.param_missed, "the value must not null",             this.name);       }       throw argumentexception.createex(errorcode.param_bad, "the value must match pattern: "           + this.validator.pattern(), this.name);     }   }    /**    * parse parameters value given string value according {@link #type}. additional    * value checked {@link #matchex(string)}.    *    * @param valuestr <i>optional</i> - string value parse value    * @return parsed value, may <code>null</code>    * @throws argumentexception in case parameter:    *           <ul>    *           <li>does not {@link #matchex(string)} {@link #validator}</li>    *           <li>cannot parsed according {@link #type}</li>    *           </ul>    * @throws internalserviceexception in case type {@link #type} cannot handled.    *           programming error.    */   @override   public t parse(final string valuestr) throws argumentexception, internalserviceexception {     if (null == valuestr) {       return null;     }     this.matchex(valuestr);      if (string.class == this.type) {       return this.type.cast(valuestr);     }     if (boolean.class == this.type) {       return this.type.cast(boolean.valueof(("1".equals(valuestr)) || boolean.valueof(valuestr)));     }     try {       if (integer.class == this.type) {         return this.type.cast(integer.valueof(valuestr));       }       if (long.class == this.type) {         return this.type.cast(long.valueof(valuestr));       }     } catch (final numberformatexception e) {       throw argumentexception.createex(errorcode.param_bad, "the value cannot parsed "           + this.type.getsimplename().tolowercase() + ".", this.name);     }      return this.parseother(valuestr);   }    /**    * field access {@link #name}.    *    * @return value of {@link #name}.    */   @override   public string getname() {     return this.name;   }    /**    * field access {@link #type}.    *    * @return value of {@link #type}.    */   @override   public class<t> gettype() {     return this.type;   }    /**    * {@inheritdoc}    */   @override   public final string tostring(final object value) throws internalserviceexception {     if (false == this.type.isassignablefrom(value.getclass())) {       throw new internalserviceexception(errorcode.panic,           "parameter.tostring(): bad type of value. expected {0} {1}.", this.type.getname(),           value.getclass().getname());     }     if (string.class == this.type || integer.class == this.type || long.class == this.type) {       return string.valueof(value);     }     if (boolean.class == this.type) {       return boolean.true.equals(value) ? "1" : "0";     }      return this.tostringother(value);   }    /**    * parse parameter values of other (non standard types). method called    * {@link #parse(string)} in case {@link #type} none of supported standard types (currently    * string, boolean, integer , long). intended extensions.    * <dl>    * <dt style="margin-top:0.25cm;"><i>note:</i>    * <dd>this default implementation throws internalserviceexception.    * </dl>    *    * @param valuestr <i>mandatory</i> - string value parse value    * @return parsed value, may <code>null</code>    * @throws argumentexception in case parameter cannot parsed according {@link #type}    * @throws internalserviceexception in case type {@link #type} cannot handled.    *           programming error.    */   protected t parseother(final string valuestr) throws argumentexception, internalserviceexception {     throw new internalserviceexception(errorcode.panic,         "parameterimpl.parseother(): unsupported parameter type: " + this.type.getname());   }    /**    * convert values of other (non standard types) external form. method called    * {@link #tostring(object)} in case {@link #type} none of supported standard types    * (currently string, boolean, integer , long). intended extensions.    * <dl>    * <dt style="margin-top:0.25cm;"><i>note:</i>    * <dd>this default implementation throws internalserviceexception.    * </dl>    *    * @param value <i>mandatory</i> - parameters value    * @return external form of parameters value, never <code>null</code>    * @throws internalserviceexception in case given <code>value</code> not match    *           {@link #getclass()}    */   protected string tostringother(final object value) throws internalserviceexception {     throw new internalserviceexception(errorcode.panic,         "parameterimpl.tostringother(): unsupported parameter type: " + this.type.getname());   } } 

Comments

Popular posts from this blog

aws api gateway - SerializationException in posting new Records via Dynamodb Proxy Service in API -

asp.net - Problems sending emails from forum -