View Javadoc

1   package com.sun.syndication.feed.synd.impl;
2   
3   import com.sun.syndication.common.CopyFrom;
4   import com.sun.syndication.common.Enum;
5   
6   import java.beans.BeanInfo;
7   import java.beans.Introspector;
8   import java.beans.PropertyDescriptor;
9   import java.lang.reflect.Array;
10  import java.lang.reflect.Method;
11  import java.util.*;
12  
13  /***
14   * @author Alejandro Abdelnur
15   */
16  public class SyndCopyFrom {
17      private static final Object[] NO_PARAMS = new Object[0];
18  
19      private Class _beanInterfaceClass;
20      private Map _baseInterfaceMap; //ENTRIES(propertyName,interface.class)
21      private Map _baseImplMap;      //ENTRIES(interface.class,implementation.class)
22  
23      public SyndCopyFrom(Class beanInterfaceClass,Map basePropInterfaceMap,Map basePropClassImplMap) {
24          _beanInterfaceClass = beanInterfaceClass;
25          _baseInterfaceMap = basePropInterfaceMap;
26          _baseImplMap = basePropClassImplMap;
27      }
28  
29      public void copy(Object target,Object source) {
30          try {
31              BeanInfo bi = Introspector.getBeanInfo(_beanInterfaceClass);
32              PropertyDescriptor[] pds = bi.getPropertyDescriptors();
33              if (pds!=null) {
34                  for (int i=0;i<pds.length;i++) {
35                      String propertyName = pds[i].getName();
36                      Method pReadMethod = pds[i].getReadMethod();
37                      Method pWriteMethod = pds[i].getWriteMethod();
38                      if (pReadMethod!=null && pWriteMethod!=null &&       // ensure it has getter and setter methods
39                          pReadMethod.getDeclaringClass()!=Object.class && // filter Object.class getter methods
40                          pReadMethod.getParameterTypes().length==0 &&     // filter getter methods that take parameters
41                          _baseInterfaceMap.containsKey(propertyName)) {   // only copies properties defined as copyFrom-able
42                          Object value = pReadMethod.invoke(source,NO_PARAMS);
43                          if (value!=null) {
44                              Class baseInterface = (Class) _baseInterfaceMap.get(propertyName);
45                              value = doCopy(value,baseInterface);
46                              pWriteMethod.invoke(target,new Object[]{value});
47                          }
48                      }
49                  }
50              }
51          }
52          catch (Exception ex) {
53              System.out.println(ex);
54              ex.printStackTrace(System.out);
55              throw new RuntimeException("Could not do a copyFrom "+ex);
56          }
57      }
58  
59      private CopyFrom createInstance(Class interfaceClass) throws Exception {
60          return (CopyFrom) ((Class)_baseImplMap.get(interfaceClass)).newInstance();
61      }
62  
63      private Object doCopy(Object value,Class baseInterface) throws Exception {
64          if (value!=null) {
65              Class vClass = value.getClass();
66              if (vClass.isArray()) {
67                  value = doCopyArray(value,baseInterface);
68              }
69              else
70              if (value instanceof Collection) {
71                  value = doCopyCollection((Collection)value,baseInterface);
72              }
73              else
74              if (value instanceof Map) {
75                  value = doCopyMap((Map)value,baseInterface);
76              }
77              else
78              if (isBasicType(vClass)) {
79                  // value = value; // nothing to do here
80                  if (value instanceof Date) { // because Date it is not inmutable 
81                      value = ((Date)value).clone();
82                  }
83              }
84              else { // it goes CopyFrom
85                  if (value instanceof CopyFrom) {
86                      CopyFrom source = (CopyFrom)value;
87                      CopyFrom target = createInstance(source.getInterface());
88                      target.copyFrom(source);
89                      value = target;
90                  }
91                  else {
92                      throw new Exception("unsupported class for 'copyFrom' "+value.getClass());
93                  }
94              }
95          }
96          return value;
97      }
98  
99      private Object doCopyArray(Object array,Class baseInterface) throws Exception {
100         Class elementClass = array.getClass().getComponentType();
101         int length = Array.getLength(array);
102         Object newArray = Array.newInstance(elementClass,length);
103         for (int i=0;i<length;i++) {
104             Object element = doCopy(Array.get(array,i),baseInterface);
105             Array.set(newArray,i,element);
106         }
107         return newArray;
108     }
109 
110     private Object doCopyCollection(Collection collection,Class baseInterface) throws Exception {
111         // expecting SETs or LISTs only, going default implementation of them
112         Collection newColl = (collection instanceof Set) ? (Collection)new HashSet() : (Collection)new ArrayList();
113         Iterator i = collection.iterator();
114         while (i.hasNext()) {
115             Object element = doCopy(i.next(),baseInterface);
116             newColl.add(element);
117         }
118         return newColl;
119     }
120 
121     private Object doCopyMap(Map map,Class baseInterface) throws Exception {
122         Map newMap = new HashMap();
123         Iterator entries = map.entrySet().iterator();
124         while (entries.hasNext()) {
125             Map.Entry entry = (Map.Entry) entries.next();
126             Object key = entry.getKey(); // we are assuming string KEYS
127             Object element = doCopy(entry.getValue(),baseInterface);
128             newMap.put(key,element);
129         }
130         return newMap;
131     }
132 
133     private static final Set BASIC_TYPES = new HashSet();
134 
135     static {
136         BASIC_TYPES.add(Boolean.class);
137         BASIC_TYPES.add(Byte.class);
138         BASIC_TYPES.add(Character.class);
139         BASIC_TYPES.add(Double.class);
140         BASIC_TYPES.add(Float.class);
141         BASIC_TYPES.add(Integer.class);
142         BASIC_TYPES.add(Long.class);
143         BASIC_TYPES.add(Short.class);
144         BASIC_TYPES.add(String.class);
145         BASIC_TYPES.add(Date.class);
146     }
147 
148     private boolean isBasicType(Class vClass) {
149         return BASIC_TYPES.contains(vClass) || Enum.class.isAssignableFrom(vClass);
150     }
151 
152 }