openwfe.org.util.beancoder.AbstractBeanCoder Maven / Gradle / Ivy
/*
* Copyright (c) 2006, John Mettraux, OpenWFE.org
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name of the "OpenWFE" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: ReflectionUtils.java 2673 2006-05-26 21:08:46Z jmettraux $
*/
//
// AbstractBeanCoder.java
//
// [email protected]
//
// generated with
// jtmpl 1.1.01 2004/05/19 ([email protected])
//
package openwfe.org.util.beancoder;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import openwfe.org.util.ReflectionUtils;
/**
* A foundation class for the bean coder implementations.
* This class covers all the reflection issues behind 'beancoding'.
*
* CVS Info :
*
$Author$
*
$Id$
*
* @author [email protected]
*/
public abstract class AbstractBeanCoder
implements BeanCoder
{
private final static org.apache.log4j.Logger log = org.apache.log4j.Logger
.getLogger(AbstractBeanCoder.class.getName());
//
// CONSTANTS & co
private final static String IS = "is";
private final static String SET = "set";
//
// types
protected final static int T_UNKNOWN = -2;
protected final static int T_NULL = -1;
protected final static int T_ARRAY = 0;
protected final static int T_BYTE_ARRAY = 1;
protected final static int T_MAP = 2;
protected final static int T_COLLECTION = 3;
protected final static int T_PRIMITIVE = 4;
protected final static int T_BEAN = 5;
//
// FIELDS
//
// CONSTRUCTORS
//
// ABSTRACT METHODS
//
// encoding
protected abstract void encodeNull ()
throws BeanCoderException;
protected abstract void encodePrimitive (Object bean)
throws BeanCoderException;
protected abstract void encodeField (String fieldName, Object value)
throws BeanCoderException;
protected abstract void encodeByteArray (byte[] array)
throws BeanCoderException;
protected abstract void encodeEntry (final int index, final Object entry)
throws BeanCoderException;
protected abstract void beginBean (Object bean)
throws BeanCoderException;
protected abstract void beginArray (int length)
throws BeanCoderException;
protected abstract void beginMap (java.util.Map map)
throws BeanCoderException;
protected abstract void beginMapEntry ()
throws BeanCoderException;
protected abstract void beginCollection (java.util.Collection col)
throws BeanCoderException;
protected abstract void endElement ()
throws BeanCoderException;
//
// decoding
protected abstract int currentType ()
throws BeanCoderException;
protected abstract String currentClassName ()
throws BeanCoderException;
protected abstract Class currentClass ()
throws BeanCoderException;
protected abstract String currentText ()
throws BeanCoderException;
protected abstract int subElementCount ()
throws BeanCoderException;
protected abstract java.util.Iterator subElementIterator ()
throws BeanCoderException;
protected abstract String currentFieldName ()
throws BeanCoderException;
protected abstract byte[] decodeByteArray ()
throws BeanCoderException;
protected abstract Object decodeFieldValue ()
throws BeanCoderException;
//
// METHODS from BeanCoder
public void encode (final Object bean)
throws BeanCoderException
{
if (bean == null)
{
encodeNull();
return;
}
//
// is it an array, a collection or a primitive ?
if (bean.getClass().isArray())
{
encodeArray(bean);
return;
}
if (java.util.Map.class.isInstance(bean))
{
encodeMap(bean);
return;
}
if (java.util.Collection.class.isInstance(bean))
{
encodeCollection(bean);
return;
}
if (BeanCoderUtils.isPrimitive(bean))
{
encodePrimitive(bean);
return;
}
encodeBean(bean);
}
public Object decode ()
throws BeanCoderException
{
final int type = currentType();
//if (log.isDebugEnabled())
// log.debug("decode() type is "+type);
if (type == T_NULL) return null;
if (type == T_ARRAY) return decodeArray();
if (type == T_BYTE_ARRAY) return decodeByteArray();
if (type == T_MAP) return decodeMap();
if (type == T_COLLECTION) return decodeCollection();
if (type == T_PRIMITIVE) return decodePrimitive();
// else...
return decodeBean();
}
//
// METHODS
// DECODING
protected Object decodePrimitive ()
throws BeanCoderException
{
final Class primitiveClass = currentClass();
final String text = currentText();
return BeanCoderUtils.newPrimitive(primitiveClass, text);
}
/**
* This method just wraps newInstance() invocation and turns potential
* exceptions into BeanCoderException.
*/
protected Object newInstance (final Class c)
throws BeanCoderException
{
try
{
return c.newInstance();
}
catch (final Exception e)
{
throw new BeanCoderException
("Failed to instantiate object of class "+c, e);
}
}
protected Object decodeBean ()
throws BeanCoderException
{
final Class beanClass = currentClass();
Object result = newInstance(beanClass);
final java.util.Map fieldMap = new java.util.HashMap();
java.util.Iterator it = subElementIterator();
while (it.hasNext())
{
it.next();
String fn = currentFieldName();
fn =
fn.substring(0, 1).toUpperCase() +
fn.substring(1);
final String setMethodName = SET + fn;
//log.debug("decodeBean() setMethodName : '"+setMethodName+"'");
final Object value = decodeFieldValue();
fieldMap.put(setMethodName, value);
}
it = ReflectionUtils.listReadWriteFields(beanClass).iterator();
while (it.hasNext())
{
final Method[] ms = (Method[])it.next();
final Method setMethod = ms[1];
final Object value = fieldMap.get(setMethod.getName());
try
{
setMethod.invoke(result, new Object[] { value });
}
catch (final Exception e)
{
String valueClassName = "null";
throw new BeanCoderException
("failed to set bean field via "+setMethod.getName()+
"() with value of class "+valueClassName,
e);
}
}
return result;
}
protected Object[] decodeArray ()
throws BeanCoderException
{
final Object[] result = new Object[subElementCount()];
int i = 0;
final java.util.Iterator it = subElementIterator();
while (it.hasNext())
{
it.next();
result[i] = decode();
i++;
}
return result;
}
protected java.util.Map decodeMap ()
throws BeanCoderException
{
final java.util.Map result =
(java.util.Map)newInstance(currentClass());
final java.util.Iterator it = subElementIterator();
while (it.hasNext())
{
it.next();
final Object[] kv = decodeMapEntry();
if (kv == null) continue;
//
// could make sense in some implementations
result.put(kv[0], kv[1]);
}
return result;
}
protected Object[] decodeMapEntry ()
throws BeanCoderException
{
Object key = null;
Object value = null;
final java.util.Iterator iit = subElementIterator();
while (iit.hasNext())
{
iit.next();
final Object o = decode();
if (key != null)
{
value = o;
break;
}
key = o;
}
return new Object[] { key, value };
}
protected java.util.Collection decodeCollection ()
throws BeanCoderException
{
final java.util.Collection result =
(java.util.Collection)newInstance(currentClass());
final java.util.Iterator it = subElementIterator();
while (it.hasNext())
{
it.next();
result.add(decode());
}
return result;
}
// ENCODING
protected String determineFieldName (final Method getMethod)
{
String fieldName = getMethod.getName();
if (fieldName.startsWith(IS))
fieldName = fieldName.substring(2);
else
fieldName = fieldName.substring(3);
fieldName =
fieldName.substring(0, 1).toLowerCase() +
fieldName.substring(1);
return fieldName;
}
protected void encodeBean (final Object bean)
throws BeanCoderException
{
beginBean(bean);
final java.util.Iterator it = ReflectionUtils
.listReadWriteFields(bean).iterator();
while (it.hasNext())
{
final Method[] methods = (Method[])it.next();
//
// this array contains
// 0 : the get method
// 1 : the set method
final Method getMethod = methods[0];
final String fieldName = determineFieldName(getMethod);
try
{
final Object[] args = null;
final Object value = getMethod.invoke(bean, args);
encodeField(fieldName, value);
}
catch (final Exception e)
{
throw new BeanCoderException
("Failed to encode field named '"+fieldName+
"' of class '"+bean.getClass().getName()+"'",
e);
}
}
endElement();
}
protected void encodeArray (final Object array)
throws BeanCoderException
{
try
{
encodeByteArray((byte[])array);
return;
}
catch (final Throwable t)
{
// it's definitively not a byte array
// so let's go on
}
final int length = Array.getLength(array);
beginArray(length);
for (int i=0; i