Type.java |
/* * $Id: Type.java,v 1.35 2010/11/18 20:35:05 agoubard Exp $ * * See the COPYRIGHT file for redistribution and use restrictions. */ package org.xins.common.types; import org.xins.common.MandatoryArgumentChecker; import org.xins.common.Utils; /** * Value type. This is an abstract base class for type classes. Each type * defines a name and it defines what values are considered valid and what * values are considered invalid. * * @version $Revision: 1.35 $ $Date: 2010/11/18 20:35:05 $ * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a> * * @since XINS 1.0.0 */ public abstract class Type { /** * The name of this type. Never <code>null</code>. */ private final String _name; /** * The class for all values. Never <code>null</code>. */ private final Class _valueClass; /** * Creates a new <code>Type</code> instance. Both the name of the type and * the value class must be specified. The value class in the class (or * interface) that values for this type should be instances of. If * <code>null</code> is specified as the value class, then that is the same * as specifying <code>Object.class</code> as the value class. * * @param name * the name of the type, not <code>null</code>. * * @param valueClass * the class or interface that values should be instances of, or * <code>null</code> if any class is valid. * * @throws IllegalArgumentException * if <code>name == null</code>. */ protected Type(String name, Class valueClass) throws IllegalArgumentException { // Check preconditions MandatoryArgumentChecker.check("name", name); // Store the arguments _name = name; _valueClass = valueClass == null ? Object.class : valueClass; } /** * Retrieves the name of this type. * * @return * the name of this type, never <code>null</code>. */ public final String getName() { return _name; } /** * Retrieves the description of this type. * * @return * the description of this type, never <code>null</code>. * * @since XINS 2.1. */ public String getDescription() { return _name + " type."; } /** * Retrieves the value class. All values for this type are instances of * this class. * * @return * the class values should be instances of, never <code>null</code>. */ public final Class getValueClass() { return _valueClass; } /** * Checks if the specified value is valid for this type and throws an * exception if not. * * <p />Note that <code>null</code> values are <em>always</em> considered * to be valid. * * @param value * the value that should be checked for validity, can be * <code>null</code>. * * @throws TypeValueException * if the specified value is invalid for this type. */ public final void checkValue(String value) throws TypeValueException { if (value == null) { return; } else if (! isValidValueImpl(value)) { throw new TypeValueException(this, value); } } /** * Determines if the specified <code>String</code> value is considered * valid for this type (wrapper method). * * <p />This method first checks if <code>string == null</code> and if it * is not, then it returns the result of a call to * {@link #isValidValueImpl(String)}. Note that <code>null</code> values * are <em>always</em> considered to be valid. * * @param string * the value that should be checked for validity, can be * <code>null</code>. * * @return * <code>true</code> if and only if the specified value is valid, * <code>false</code> otherwise. */ public final boolean isValidValue(String string) { if (string == null || string.length() == 0) { return true; } else { return isValidValueImpl(string); } } /** * Determines if the specified <code>String</code> value is considered * valid for this type (implementation method). * * <p>This method is called from {@link #isValidValue(String)}. When * called from that method, it is guaranteed that the argument is not * <code>null</code>. * * <p />The implementation of this method in class {@link Type} returns * <code>true</code>. * * @param string * the <code>String</code> value that should be checked for validity, * never <code>null</code>. * * @return * <code>true</code> if and only if the specified <code>String</code> * value is valid, <code>false</code> otherwise. */ protected boolean isValidValueImpl(String string) { return true; } /** * Converts from a <code>String</code> to an instance of the value class * for this type (wrapper method). * * <p />This method returns <code>null</code> if <code>string == * null</code>. Otherwise it first calls {@link #isValidValueImpl(String)} * to check if the value is in principle valid. If it is, then * {@link #fromStringImpl(String)} is called. If the result of that call is * <em>not</em> an instance of the value class, then an * {@link Error} is thrown. Notice that this error is also thrown * if {@link #fromStringImpl(String)} returns <code>null</code>. * * @param string * the string to convert to an instance of the value class, can be * <code>null</code>. * * @return * an instance of the value class, will be <code>null</code> if and only * if <code>string == null</code>. * * @throws TypeValueException * if the specified string does not represent a valid value for this * type. */ public final Object fromString(String string) throws TypeValueException { if (string == null) { return null; } Object value = fromStringImpl(string); // TODO: Create a unit test to check that a null returned from // fromStringImpl(String) is actually causing a // ProgrammingException to be thrown if (!_valueClass.isInstance(value)) { String detail = "The value returned is an instance of class " + value.getClass().getName() + " instead of an instance of " + _valueClass.getName() + '.'; throw Utils.logProgrammingError(detail); } return value; } /** * Converts from a <code>String</code> to an instance of the value class * for this type (implementation method). * * <p>This method is not required to check the validity of the specified * value (since {@link #isValidValueImpl(String)} should have been called * before) but if it does, then it may throw a {@link TypeValueException}. * * @param string * the string to convert to an instance of the value class, guaranteed * to be not <code>null</code> and guaranteed to have been passed to * {@link #isValidValueImpl(String)} without getting an exception. * * @return * an instance of the value class, cannot be <code>null</code>. * * @throws TypeValueException * if <code>string</code> is considered to be an invalid value for this * type. */ protected abstract Object fromStringImpl(String string) throws TypeValueException; /** * Generates a string representation of the specified value for this type. * The specified value must be an instance of the value class for this type * (see {@link #getValueClass()}). Also, it may have to fall within a * certain range of valid values, depending on the type. * * <p>The default implementation of this method in class {@link Type} does * the following: * * <ul> * <li>if <code>value == null</code> then it throws an * {@link IllegalArgumentException}; * <li>if <code>getValueClass().isInstance(value) == false</code> then * it throws a {@link ClassCastException}; * <li>otherwise it returns * <code>value.</code>{@link Object#toString()}. * </ul> * * @param value * the value, cannot be <code>null</code>. * * @return * the string representation of the specified value for this type, * cannot be <code>null</code>. * * @throws IllegalArgumentException * if <code>value == null</code>. * * @throws ClassCastException * if <code>getValueClass().isInstance(value) == false</code>. * * @throws TypeValueException * if the specified value is not in the allowed range. */ public String toString(Object value) throws IllegalArgumentException, ClassCastException, TypeValueException { // Check preconditions MandatoryArgumentChecker.check("value", value); if (!getValueClass().isInstance(value)) { throw new ClassCastException(); } return value.toString(); } /** * Returns a textual presentation of this object. The implementation of * this method just returns the name of this type. * * @return * the textual presentation, never <code>null</code>. */ public final String toString() { return _name; } }