001: /*
002: * Copyright 2004 Sun Microsystems, Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: *
016: */
017: package com.sun.syndication.feed.impl;
018:
019: import com.sun.syndication.feed.CopyFrom;
020: import com.sun.syndication.feed.impl.BeanIntrospector;
021:
022: import java.beans.PropertyDescriptor;
023: import java.lang.reflect.Array;
024: import java.lang.reflect.Method;
025: import java.util.*;
026:
027: /**
028: * @author Alejandro Abdelnur
029: */
030: public class CopyFromHelper {
031: private static final Object[] NO_PARAMS = new Object[0];
032:
033: private Class _beanInterfaceClass;
034: private Map _baseInterfaceMap; //ENTRIES(propertyName,interface.class)
035: private Map _baseImplMap; //ENTRIES(interface.class,implementation.class)
036:
037: public CopyFromHelper(Class beanInterfaceClass,
038: Map basePropInterfaceMap, Map basePropClassImplMap) {
039: _beanInterfaceClass = beanInterfaceClass;
040: _baseInterfaceMap = basePropInterfaceMap;
041: _baseImplMap = basePropClassImplMap;
042: }
043:
044: public void copy(Object target, Object source) {
045: try {
046: PropertyDescriptor[] pds = BeanIntrospector
047: .getPropertyDescriptors(_beanInterfaceClass);
048: if (pds != null) {
049: for (int i = 0; i < pds.length; i++) {
050: String propertyName = pds[i].getName();
051: Method pReadMethod = pds[i].getReadMethod();
052: Method pWriteMethod = pds[i].getWriteMethod();
053: if (pReadMethod != null
054: && pWriteMethod != null
055: && // ensure it has getter and setter methods
056: pReadMethod.getDeclaringClass() != Object.class
057: && // filter Object.class getter methods
058: pReadMethod.getParameterTypes().length == 0
059: && // filter getter methods that take parameters
060: _baseInterfaceMap.containsKey(propertyName)) { // only copies properties defined as copyFrom-able
061: Object value = pReadMethod.invoke(source,
062: NO_PARAMS);
063: if (value != null) {
064: Class baseInterface = (Class) _baseInterfaceMap
065: .get(propertyName);
066: value = doCopy(value, baseInterface);
067: pWriteMethod.invoke(target,
068: new Object[] { value });
069: }
070: }
071: }
072: }
073: } catch (Exception ex) {
074: throw new RuntimeException("Could not do a copyFrom " + ex,
075: ex);
076: }
077: }
078:
079: private CopyFrom createInstance(Class interfaceClass)
080: throws Exception {
081: if (_baseImplMap.get(interfaceClass) == null) {
082: return null;
083: } else {
084: return (CopyFrom) ((Class) _baseImplMap.get(interfaceClass))
085: .newInstance();
086: }
087: }
088:
089: private Object doCopy(Object value, Class baseInterface)
090: throws Exception {
091: if (value != null) {
092: Class vClass = value.getClass();
093: if (vClass.isArray()) {
094: value = doCopyArray(value, baseInterface);
095: } else if (value instanceof Collection) {
096: value = doCopyCollection((Collection) value,
097: baseInterface);
098: } else if (value instanceof Map) {
099: value = doCopyMap((Map) value, baseInterface);
100: } else if (isBasicType(vClass)) {
101: // value = value; // nothing to do here
102: if (value instanceof Date) { // because Date it is not inmutable
103: value = ((Date) value).clone();
104: }
105: } else { // it goes CopyFrom
106: if (value instanceof CopyFrom) {
107: CopyFrom source = (CopyFrom) value;
108: CopyFrom target = createInstance(source
109: .getInterface());
110: target = target == null ? (CopyFrom) value
111: .getClass().newInstance() : target;
112: target.copyFrom(source);
113: value = target;
114: } else {
115: throw new Exception(
116: "unsupported class for 'copyFrom' "
117: + value.getClass());
118: }
119: }
120: }
121: return value;
122: }
123:
124: private Object doCopyArray(Object array, Class baseInterface)
125: throws Exception {
126: Class elementClass = array.getClass().getComponentType();
127: int length = Array.getLength(array);
128: Object newArray = Array.newInstance(elementClass, length);
129: for (int i = 0; i < length; i++) {
130: Object element = doCopy(Array.get(array, i), baseInterface);
131: Array.set(newArray, i, element);
132: }
133: return newArray;
134: }
135:
136: private Object doCopyCollection(Collection collection,
137: Class baseInterface) throws Exception {
138: // expecting SETs or LISTs only, going default implementation of them
139: Collection newColl = (collection instanceof Set) ? (Collection) new HashSet()
140: : (Collection) new ArrayList();
141: Iterator i = collection.iterator();
142: while (i.hasNext()) {
143: Object element = doCopy(i.next(), baseInterface);
144: newColl.add(element);
145: }
146: return newColl;
147: }
148:
149: private Object doCopyMap(Map map, Class baseInterface)
150: throws Exception {
151: Map newMap = new HashMap();
152: Iterator entries = map.entrySet().iterator();
153: while (entries.hasNext()) {
154: Map.Entry entry = (Map.Entry) entries.next();
155: Object key = entry.getKey(); // we are assuming string KEYS
156: Object element = doCopy(entry.getValue(), baseInterface);
157: newMap.put(key, element);
158: }
159: return newMap;
160: }
161:
162: private static final Set BASIC_TYPES = new HashSet();
163:
164: static {
165: BASIC_TYPES.add(Boolean.class);
166: BASIC_TYPES.add(Byte.class);
167: BASIC_TYPES.add(Character.class);
168: BASIC_TYPES.add(Double.class);
169: BASIC_TYPES.add(Float.class);
170: BASIC_TYPES.add(Integer.class);
171: BASIC_TYPES.add(Long.class);
172: BASIC_TYPES.add(Short.class);
173: BASIC_TYPES.add(String.class);
174: BASIC_TYPES.add(Date.class);
175: }
176:
177: private boolean isBasicType(Class vClass) {
178: return BASIC_TYPES.contains(vClass);
179: }
180:
181: }
|