| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package flex.messaging.io; |
| |
| import flex.messaging.MessageException; |
| import flex.messaging.log.Log; |
| import flex.messaging.log.Logger; |
| import flex.messaging.util.ClassUtil; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * 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. |
| */ |
| 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} |
| */ |
| @Override |
| 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} |
| */ |
| @Override |
| 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) |
| value = getMapValue((Map) instance, propertyName); |
| |
| return value; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| 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) { |
| ClassUtil.validateAssignment(instance, propertyName, value); |
| ((Map) instance).put(propertyName, value); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected boolean ignorePropertyErrors(SerializationContext context) { |
| return true; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| protected String getClassName(Object instance) { |
| return (instance != null && instance instanceof Map |
| && instance.getClass().getName().startsWith("java.util.")) ? |
| null : super.getClassName(instance); |
| } |
| |
| /** |
| * Given a map and a property name, returns the value keyed under that property |
| * name but instead of depending on {@link Map#get(Object)}, propertyName |
| * is compared against key#toString. This is due to the fact that propertyNames |
| * are always stored as Strings. |
| * |
| * @param map The Map to check against. |
| * @param propertyName The property name to check for. |
| * @return The value keyed under property name or null if it does not exist. |
| */ |
| protected Object getMapValue(Map map, String propertyName) { |
| for (Object entry : map.entrySet()) { |
| Object key = ((Map.Entry) entry).getKey(); |
| if (key.toString().equals(propertyName)) |
| return ((Map.Entry) entry).getValue(); |
| } |
| return null; |
| } |
| } |