/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2002 - 2007 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated
* and its suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package flex.messaging.io;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
import flex.messaging.MessageException;
import flex.messaging.log.Log;
import flex.messaging.log.Logger;
/**
* Proxies serialization of a Map and considers all keys as String based property
* names. Additionally, bean properties from the instance are also included and
* override any Map entries with the same key name.
*
* @author Peter Farland
*/
public class MapProxy extends BeanProxy
{
static final long serialVersionUID = 7857999941099335210L;
private static final int NULL_KEY_ERROR = 10026;
/**
* Constructor
*/
public MapProxy()
{
super();
//dynamic = true;
}
/**
* Construct with a default instance type.
* @param defaultInstance defines the alias if provided
*/
public MapProxy(Object defaultInstance)
{
super(defaultInstance);
//dynamic = true;
}
/** {@inheritDoc} */
public List getPropertyNames(Object instance)
{
if (instance == null)
return null;
List propertyNames = null;
List excludes = null;
if (descriptor != null)
{
excludes = descriptor.getExcludesForInstance(instance);
if (excludes == null) // For compatibility with older implementations
excludes = descriptor.getExcludes();
}
// Add all Map keys as properties
if (instance instanceof Map)
{
Map map = (Map)instance;
if (map.size() > 0)
{
propertyNames = new ArrayList(map.size());
SerializationContext context = getSerializationContext();
Iterator it = map.keySet().iterator();
while (it.hasNext())
{
Object key = it.next();
if (key != null)
{
if (excludes != null && excludes.contains(key))
continue;
propertyNames.add(key.toString());
}
else
{
// Log null key errors
if (Log.isWarn() && context.logPropertyErrors)
{
Logger log = Log.getLogger(LOG_CATEGORY);
log.warn("Cannot send a null Map key for type {0}.",
new Object[] {map.getClass().getName()});
}
if (!context.ignorePropertyErrors)
{
// Cannot send a null Map key for type {0}.
MessageException ex = new MessageException();
ex.setMessage(NULL_KEY_ERROR, new Object[] {map.getClass().getName()});
throw ex;
}
}
}
}
}
// Then, check for bean properties
List beanProperties = super.getPropertyNames(instance);
if (beanProperties != null)
{
if (propertyNames == null)
{
propertyNames = beanProperties;
}
else
{
propertyNames.addAll(beanProperties);
}
}
return propertyNames;
}
/** {@inheritDoc} */
public Object getValue(Object instance, String propertyName)
{
if (instance == null || propertyName == null)
return null;
Object value = null;
// First, check for bean property
BeanProperty bp = getBeanProperty(instance, propertyName);
if (bp != null)
{
value = super.getBeanValue(instance, bp);
}
// Then check for Map entry
if (value == null && instance instanceof Map)
{
Map map = (Map)instance;
value = map.get(propertyName);
}
return value;
}
/** {@inheritDoc} */
public void setValue(Object instance, String propertyName, Object value)
{
if (instance == null || propertyName == null)
return;
Map props = getBeanProperties(instance);
if (props.containsKey(propertyName))
{
super.setValue(instance, propertyName, value);
}
else if (instance instanceof Map)
{
((Map)instance).put(propertyName, value);
}
}
/** {@inheritDoc} */
public Object clone()
{
return super.clone();
}
/** {@inheritDoc} */
protected boolean ignorePropertyErrors(SerializationContext context)
{
return true;
}
/** {@inheritDoc} */
protected boolean logPropertyErrors(SerializationContext context)
{
return false;
}
/**
* Return the classname of the instance, including ASObject types.
* If the instance is a Map and is in the java.util package, we return null.
* @param instance the object to find the class name of
* @return the class name of the object.
*/
protected String getClassName(Object instance)
{
if (instance != null && instance instanceof Map
&& instance.getClass().getName().startsWith("java.util."))
{
return null;
}
return super.getClassName(instance);
}
}