1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.sf.ezmorph.bean;
18
19 import java.beans.PropertyDescriptor;
20 import java.lang.reflect.InvocationTargetException;
21 import java.util.Collection;
22 import java.util.Map;
23
24 import net.sf.ezmorph.MorphException;
25 import net.sf.ezmorph.MorpherRegistry;
26 import net.sf.ezmorph.ObjectMorpher;
27 import net.sf.ezmorph.object.IdentityObjectMorpher;
28
29 import org.apache.commons.beanutils.DynaBean;
30 import org.apache.commons.beanutils.DynaProperty;
31 import org.apache.commons.beanutils.PropertyUtils;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34
35
36
37
38
39
40
41
42
43
44
45
46 public final class BeanMorpher implements ObjectMorpher
47 {
48 private static final Log log = LogFactory.getLog( BeanMorpher.class );
49 private final Class beanClass;
50 private boolean lenient;
51 private final MorpherRegistry morpherRegistry;
52
53
54
55
56
57 public BeanMorpher( Class beanClass, MorpherRegistry morpherRegistry )
58 {
59 this( beanClass, morpherRegistry, false );
60 }
61
62
63
64
65
66
67
68 public BeanMorpher( Class beanClass, MorpherRegistry morpherRegistry, boolean lenient )
69 {
70 validateClass( beanClass );
71 if( morpherRegistry == null ){
72 throw new MorphException( "morpherRegistry is null" );
73 }
74 this.beanClass = beanClass;
75 this.morpherRegistry = morpherRegistry;
76 this.lenient = lenient;
77 }
78
79 public Object morph( Object sourceBean )
80 {
81 if( sourceBean == null ){
82 return null;
83 }
84 if( !supports( sourceBean.getClass() ) ){
85 throw new MorphException( "unsupported class: " + sourceBean.getClass()
86 .getName() );
87 }
88
89 Object targetBean = null;
90
91 try{
92 targetBean = beanClass.newInstance();
93 PropertyDescriptor[] targetPds = PropertyUtils.getPropertyDescriptors( beanClass );
94 for( int i = 0; i < targetPds.length; i++ ){
95 PropertyDescriptor targetPd = targetPds[i];
96 String name = targetPd.getName();
97 if( targetPd.getWriteMethod() == null ){
98 log.info( "Property '" + beanClass.getName() + "." + name
99 + "' has no write method. SKIPPED." );
100 continue;
101 }
102
103 Class sourceType = null;
104 if( sourceBean instanceof DynaBean ){
105 DynaBean dynaBean = (DynaBean) sourceBean;
106 DynaProperty dynaProperty = dynaBean.getDynaClass()
107 .getDynaProperty( name );
108 if( dynaProperty == null ){
109 log.warn( "DynaProperty '" + name + "' does not exist. SKIPPED." );
110 continue;
111 }
112 sourceType = dynaProperty.getType();
113 }else{
114 PropertyDescriptor sourcePd = PropertyUtils.getPropertyDescriptor( sourceBean, name );
115 if( sourcePd == null ){
116 log.warn( "Property '" + sourceBean.getClass()
117 .getName() + "." + name + "' does not exist. SKIPPED." );
118 continue;
119 }else if( sourcePd.getReadMethod() == null ){
120 log.warn( "Property '" + sourceBean.getClass()
121 .getName() + "." + name + "' has no read method. SKIPPED." );
122 continue;
123 }
124 sourceType = sourcePd.getPropertyType();
125 }
126
127 Class targetType = targetPd.getPropertyType();
128 Object value = PropertyUtils.getProperty( sourceBean, name );
129 setProperty( targetBean, name, sourceType, targetType, value );
130 }
131 }
132 catch( MorphException me ){
133 throw me;
134 }
135 catch( Exception e ){
136 throw new MorphException( e );
137 }
138
139 return targetBean;
140 }
141
142 public Class morphsTo()
143 {
144 return beanClass;
145 }
146
147 public boolean supports( Class clazz )
148 {
149 return !clazz.isArray();
150 }
151
152 private void setProperty( Object targetBean, String name, Class sourceType, Class targetType,
153 Object value ) throws IllegalAccessException, InvocationTargetException,
154 NoSuchMethodException
155 {
156 if( targetType.isAssignableFrom( sourceType ) ){
157 if( value == null && targetType.isPrimitive() ){
158 value = morpherRegistry.morph( targetType, value );
159 }
160 PropertyUtils.setProperty( targetBean, name, value );
161 }else{
162 if( targetType.equals( Object.class ) ){
163
164 PropertyUtils.setProperty( targetBean, name, value );
165 }else{
166 if( value == null ){
167 if( targetType.isPrimitive() ){
168 PropertyUtils.setProperty( targetBean, name, morpherRegistry.morph( targetType,
169 value ) );
170 }
171 }else{
172 if( IdentityObjectMorpher.getInstance() == morpherRegistry.getMorpherFor( targetType ) ){
173 if( !lenient ){
174 throw new MorphException( "Can't find a morpher for target class "
175 + targetType.getName() + " (" + name + ")" );
176 }else{
177 log.info( "Can't find a morpher for target class " + targetType.getName()
178 + " (" + name + ") SKIPPED" );
179 }
180 }else{
181 PropertyUtils.setProperty( targetBean, name, morpherRegistry.morph( targetType,
182 value ) );
183 }
184 }
185 }
186 }
187 }
188
189 private void validateClass( Class clazz )
190 {
191 if( clazz == null ){
192 throw new MorphException( "target class is null" );
193 }else if( clazz.isPrimitive() ){
194 throw new MorphException( "target class is a primitive" );
195 }else if( clazz.isArray() ){
196 throw new MorphException( "target class is an array" );
197 }else if( clazz.isInterface() ){
198 throw new MorphException( "target class is an interface" );
199 }else if( DynaBean.class.isAssignableFrom( clazz ) ){
200 throw new MorphException( "target class is a DynaBean" );
201 }else if( Number.class.isAssignableFrom( clazz ) || Boolean.class.isAssignableFrom( clazz )
202 || Character.class.isAssignableFrom( clazz ) ){
203 throw new MorphException( "target class is a wrapper" );
204 }else if( String.class.isAssignableFrom( clazz ) ){
205 throw new MorphException( "target class is a String" );
206 }else if( Collection.class.isAssignableFrom( clazz ) ){
207 throw new MorphException( "target class is a Collection" );
208 }else if( Map.class.isAssignableFrom( clazz ) ){
209 throw new MorphException( "target class is a Map" );
210 }
211 }
212 }