Thank you Marko,
I did pretty much the same yesterday, but I am only using one class for all my type
safe enumeration classes.
It involves using a lot reflection so it may be very slow. Tell me what you think
about this solution.
/**
* The class EnumStringFieldHandler is a generic <code>FieldHandler</code> for
* <i>type safe enumeration</i>.
* This <i>type safe enumeration</i> class <b>must</b> have a <code>public String
toString()</code> method.
*
* @alias EnumStringFieldHandler
*/
public class EnumStringFieldHandler extends AbstractFieldHandler
{
/**
* Returns the value of the field from the object. The object should have a method
named
* <code>"get" + getFieldDescriptor().getFieldName()</code>.<br>
* <b>Example</b> : Field name = <code>identification</code>, method name =
<code>getIdentification()</code>.
* This getter should return the <i>typesafe enum</i> static instance.
* @param o The object
* @return The value of the field
* @throws IllegalStateException The Java object has changed and is no longer
supported by this handler,
* or the handler is not compatible with the Java
object
*/
public Object getValue(final Object o) throws IllegalStateException
{
final FieldDescriptor fd = getFieldDescriptor();
final String name = fd.getFieldName();
final String methodName = "get".concat(name.substring(0,
1).toUpperCase()).concat(name.substring(1,
name.length()));
try
{
final Method method = o.getClass().getMethod(methodName, new Class[]{});
return (method.invoke(o, new Object[]{})).toString();
}
catch (NoSuchMethodException e)
{
e.printStackTrace();
throw new IllegalStateException("Class " + o.getClass() + " must have
method " + methodName);
}
catch (IllegalAccessException e)
{
e.printStackTrace();
throw new IllegalStateException("Method " + methodName + " from class " +
o.getClass() + " must be public");
}
catch (InvocationTargetException e)
{
e.printStackTrace();
throw new IllegalStateException("Method " + methodName + " from class " +
o.getClass() +
" threw an exception");
}
}
/**
* Sets the value of the field on the object.
* The object should have a field name <code>"_" +
getFieldDescriptor().getFieldName()</code>.<br>
* <b>Example</b> : Field name = <code>identification</code>, object field name =
<code>_identification</code>.
* @param o The object
* @param o1 The new value
* @throws IllegalStateException The Java object has changed and is no longer
supported by this handler, or the
* handler is not compatible with the Java object
* @throws IllegalArgumentException
*/
public void setValue(final Object o, final Object o1) throws
IllegalStateException, IllegalArgumentException
{
final FieldDescriptor fd = getFieldDescriptor();
String name = fd.getFieldName();
final String methodName = "set".concat(name.substring(0,
1).toUpperCase()).concat(name.substring(1,
name.length()));
name = "_".concat(name);
Class fieldClass = null;
try
{
fieldClass = o.getClass().getDeclaredField(name).getType();
final Field[] fields = fieldClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
if (fields[i].get(null).toString().equals(o1.toString()))
{
final Method method = o.getClass().getMethod(methodName, new
Class[]{fields[i].getType()});
method.invoke(o, new Object[]{fields[i].get(null)});
break;
}
}
}
catch (NoSuchFieldException e)
{
e.printStackTrace();
throw new IllegalStateException("Field " + name + " must exist in " +
o.getClass());
}
catch (NoSuchMethodException e)
{
e.printStackTrace();
throw new IllegalStateException("Method " + methodName + " must exist in "
+ o.getClass());
}
catch (IllegalAccessException e)
{
e.printStackTrace();
throw new IllegalStateException("Class " + fieldClass.getClass() + " must
be accessible");
}
catch (InvocationTargetException e)
{
e.printStackTrace();
throw new IllegalStateException("Method " + methodName + " from class " +
fieldClass.getClass() +
" threw an exception");
}
}
/**
* Creates a new instance of the object described by this field.
* @param o The object for which the field is created
* @return A new instance of the field's value
* @throws IllegalStateException This field is a simple type and cannot be
instantiated
*/
public Object newInstance(final Object o) throws IllegalStateException
{
throw new UnsupportedOperationException();
}
/**
* Creates a new instance of the object described by this field.
* @param o The object for which the field is created
* @param objects The set of constructor arguments
* @return A new instance of the field's value
* @throws IllegalStateException This field is a simple type and cannot be
instantiated
*/
public Object newInstance(final Object o, final Object[] objects) throws
IllegalStateException
{
throw new UnsupportedOperationException();
}
/**
* Sets the value of the field to a default value.
* Reference fields are set to null, primitive fields are set to their default
value,
* collection fields are emptied of all elements.
* @param o The object
* @throws IllegalStateException The Java object has changed and is no longer
supported by this handler,
* or the handler is not compatiale with the Java
object
* @throws IllegalArgumentException
*/
public void resetValue(final Object o) throws IllegalStateException,
IllegalArgumentException
{
throw new UnsupportedOperationException();
}
}
-----Original Message-----
From: Marko Topolnik [mailto:[EMAIL PROTECTED]
Sent: 9 mars, 2004 08:16
To: [EMAIL PROTECTED]
Subject: Re: [castor-dev] typesafe enum in mapping file - how to?
Hi Carl,
I have the same problem as you. I have worked out a solution, but it is
not very elegant. It involves writing a custom ...FieldHandler class for
each typesafe enum field and for each class where such a field occurs.
For each enumField of type EnumClass in your class MyClass, you write a
field handler class like this:
public class MyEnumFieldHandler extends EnumFieldHandler
{
public Object getValue( Object object )
{
return ( (MyClass) object ).getEnumField();
}
public void setValue( Object object, Object value )
{
EnumClass enumValue = EnumClass.valueOf( (String) value );
if ( enumValue != null )
( (MyClass) object ).setEnumField( enumValue );
else
throw new RuntimeException( "Invalid value '" + value + "'" );
}
}
The base class EnumFieldHandler is derived from Castor's
AbstractFieldHandler and can be reused for all enum field handlers:
import org.exolab.castor.mapping.AbstractFieldHandler;
public abstract class EnumFieldHandler extends AbstractFieldHandler
{
public abstract void setValue( Object object, Object value );
public abstract Object getValue( Object object );
public Object newInstance( Object parent )
{
throw new UnsupportedOperationException();
}
public Object newInstance( Object parent, Object[] args )
{
throw new UnsupportedOperationException();
}
public void resetValue( Object object )
{
throw new UnsupportedOperationException();
}
}
In the mapping file, you specify:
<field name="enumField" type="EnumClass"
handler="MyEnumFieldHandler">...</field>
If anyone knows how to improve on this solution, I'd sure appreciate
their sharing it with this group!
Marko
>-----Original Message-----
>From: Letourneau, Carl [mailto:[EMAIL PROTECTED]
>Subject: Re: [castor-dev] typesafe enum in mapping file - how to?
>
>Is this possible to use a "type safe enum class" in a Mapping
>file? It keeps giving me error because I don't have a public
>default constructor on the class.
-----------------------------------------------------------
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
unsubscribe castor-dev
-----------------------------------------------------------
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
unsubscribe castor-dev