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.io.Serializable;
20 import java.lang.reflect.Array;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import net.sf.ezmorph.MorphException;
27 import net.sf.ezmorph.MorphUtils;
28 import net.sf.ezmorph.MorpherRegistry;
29
30 import org.apache.commons.beanutils.DynaBean;
31 import org.apache.commons.beanutils.DynaClass;
32 import org.apache.commons.beanutils.DynaProperty;
33 import org.apache.commons.lang.builder.EqualsBuilder;
34 import org.apache.commons.lang.builder.HashCodeBuilder;
35 import org.apache.commons.lang.builder.ToStringBuilder;
36 import org.apache.commons.lang.builder.ToStringStyle;
37
38
39
40
41 public final class MorphDynaBean implements DynaBean, Serializable
42 {
43 private static final long serialVersionUID = -605547389232706344L;
44 private MorphDynaClass dynaClass;
45 private Map dynaValues = new HashMap();
46 private MorpherRegistry morpherRegistry;
47
48 public MorphDynaBean()
49 {
50 this( null );
51 }
52
53 public MorphDynaBean( MorpherRegistry morpherRegistry )
54 {
55 setMorpherRegistry( morpherRegistry );
56 }
57
58 public boolean contains( String name, String key )
59 {
60 DynaProperty dynaProperty = getDynaProperty( name );
61
62 Class type = dynaProperty.getType();
63 if( !Map.class.isAssignableFrom( type ) ){
64 throw new MorphException( "Non-Mapped property name: " + name + " key: " + key );
65 }
66
67 Object value = dynaValues.get( name );
68 if( value == null ){
69 value = new HashMap();
70 dynaValues.put( name, value );
71 }
72 return ((Map) value).containsKey( key );
73 }
74
75 public boolean equals( Object obj )
76 {
77 if( this == obj ){
78 return true;
79 }
80
81 if( obj == null ){
82 return false;
83 }
84
85 if( !(obj instanceof MorphDynaBean) ){
86 return false;
87 }
88
89 MorphDynaBean other = (MorphDynaBean) obj;
90 EqualsBuilder builder = new EqualsBuilder().append( this.dynaClass, other.dynaClass );
91 DynaProperty[] props = dynaClass.getDynaProperties();
92 for( int i = 0; i < props.length; i++ ){
93 DynaProperty prop = props[i];
94 builder.append( dynaValues.get( prop.getName() ), dynaValues.get( prop.getName() ) );
95 }
96 return builder.isEquals();
97 }
98
99 public Object get( String name )
100 {
101 Object value = dynaValues.get( name );
102
103 if( value != null ){
104 return value;
105 }
106
107 Class type = getDynaProperty( name ).getType();
108 if( !type.isPrimitive() ){
109 return value;
110 }else{
111 return morpherRegistry.morph( type, value );
112 }
113 }
114
115 public Object get( String name, int index )
116 {
117 DynaProperty dynaProperty = getDynaProperty( name );
118
119 Class type = dynaProperty.getType();
120 if( !type.isArray() && !List.class.isAssignableFrom( type ) ){
121 throw new MorphException( "Non-Indexed property name: " + name + " index: " + index );
122 }
123
124 Object value = dynaValues.get( name );
125
126 if( value.getClass()
127 .isArray() ){
128 value = Array.get( value, index );
129 }else if( value instanceof List ){
130 value = ((List) value).get( index );
131 }
132
133 return value;
134 }
135
136 public Object get( String name, String key )
137 {
138 DynaProperty dynaProperty = getDynaProperty( name );
139
140 Class type = dynaProperty.getType();
141 if( !Map.class.isAssignableFrom( type ) ){
142 throw new MorphException( "Non-Mapped property name: " + name + " key: " + key );
143 }
144
145 Object value = dynaValues.get( name );
146 if( value == null ){
147 value = new HashMap();
148 dynaValues.put( name, value );
149 }
150 return ((Map) value).get( key );
151 }
152
153 public DynaClass getDynaClass()
154 {
155 return this.dynaClass;
156 }
157
158 public MorpherRegistry getMorpherRegistry()
159 {
160 return morpherRegistry;
161 }
162
163 public int hashCode()
164 {
165 HashCodeBuilder builder = new HashCodeBuilder().append( dynaClass );
166 DynaProperty[] props = dynaClass.getDynaProperties();
167 for( int i = 0; i < props.length; i++ ){
168 DynaProperty prop = props[i];
169 builder.append( dynaValues.get( prop.getName() ) );
170 }
171 return builder.toHashCode();
172 }
173
174 public void remove( String name, String key )
175 {
176 DynaProperty dynaProperty = getDynaProperty( name );
177
178 Class type = dynaProperty.getType();
179 if( !Map.class.isAssignableFrom( type ) ){
180 throw new MorphException( "Non-Mapped property name: " + name + " key: " + key );
181 }
182
183 Object value = dynaValues.get( name );
184 if( value == null ){
185 value = new HashMap();
186 dynaValues.put( name, value );
187 }
188 ((Map) value).remove( key );
189 }
190
191 public void set( String name, int index, Object value )
192 {
193 DynaProperty dynaProperty = getDynaProperty( name );
194
195 Class type = dynaProperty.getType();
196 if( !type.isArray() && !List.class.isAssignableFrom( type ) ){
197 throw new MorphException( "Non-Indexed property name: " + name + " index: " + index );
198 }
199
200 Object prop = dynaValues.get( name );
201 if( prop == null ){
202 if( List.class.isAssignableFrom( type ) ){
203 prop = new ArrayList();
204 }else{
205 prop = Array.newInstance( type.getComponentType(), index + 1 );
206 }
207 dynaValues.put( name, prop );
208 }
209
210 if( prop.getClass()
211 .isArray() ){
212 if( index >= Array.getLength( prop ) ){
213 Object tmp = Array.newInstance( type.getComponentType(), index + 1 );
214 System.arraycopy( prop, 0, tmp, 0, Array.getLength( prop ) );
215 prop = tmp;
216 dynaValues.put( name, tmp );
217 }
218 Array.set( prop, index, value );
219 }else if( prop instanceof List ){
220 List l = (List) prop;
221 if( index >= l.size() ){
222 for( int i = l.size(); i <= index + 1; i++ ){
223 l.add( null );
224 }
225 }
226 ((List) prop).set( index, value );
227 }
228 }
229
230 public void set( String name, Object value )
231 {
232 DynaProperty property = getDynaProperty( name );
233
234 if( value == null || !isDynaAssignable( property.getType(), value.getClass() ) ){
235 value = morpherRegistry.morph( property.getType(), value );
236 }
237
238 dynaValues.put( name, value );
239 }
240
241 public void set( String name, String key, Object value )
242 {
243 DynaProperty dynaProperty = getDynaProperty( name );
244
245 Class type = dynaProperty.getType();
246 if( !Map.class.isAssignableFrom( type ) ){
247 throw new MorphException( "Non-Mapped property name: " + name + " key: " + key );
248 }
249
250 Object prop = dynaValues.get( name );
251 if( prop == null ){
252 prop = new HashMap();
253 dynaValues.put( name, prop );
254 }
255 ((Map) prop).put( key, value );
256 }
257
258 public synchronized void setDynaBeanClass( MorphDynaClass dynaClass )
259 {
260 if( this.dynaClass == null ){
261 this.dynaClass = dynaClass;
262 }
263 }
264
265 public void setMorpherRegistry( MorpherRegistry morpherRegistry )
266 {
267 if( morpherRegistry == null ){
268 this.morpherRegistry = new MorpherRegistry();
269 MorphUtils.registerStandardMorphers( this.morpherRegistry );
270 }else{
271 this.morpherRegistry = morpherRegistry;
272 }
273 }
274
275 public String toString()
276 {
277 return new ToStringBuilder( this, ToStringStyle.MULTI_LINE_STYLE ).append( dynaValues )
278 .toString();
279 }
280
281 protected DynaProperty getDynaProperty( String name )
282 {
283 DynaProperty property = getDynaClass().getDynaProperty( name );
284 if( property == null ){
285 throw new MorphException( "Unspecified property for " + name );
286 }
287 return property;
288 }
289
290 protected boolean isDynaAssignable( Class dest, Class src )
291 {
292 boolean assignable = dest.isAssignableFrom( src );
293 if( assignable ){
294 return true;
295 }
296 assignable = (dest == Boolean.TYPE && src == Boolean.class) ? true : assignable;
297 assignable = (dest == Byte.TYPE && src == Byte.class) ? true : assignable;
298 assignable = (dest == Character.TYPE && src == Character.class) ? true : assignable;
299 assignable = (dest == Short.TYPE && src == Short.class) ? true : assignable;
300 assignable = (dest == Integer.TYPE && src == Integer.class) ? true : assignable;
301 assignable = (dest == Long.TYPE && src == Long.class) ? true : assignable;
302 assignable = (dest == Float.TYPE && src == Float.class) ? true : assignable;
303 assignable = (dest == Double.TYPE && src == Double.class) ? true : assignable;
304
305 if( src == Double.TYPE || Double.class.isAssignableFrom( src ) ){
306 assignable = (isByte( dest ) || isShort( dest ) || isInteger( dest ) || isLong( dest ) || isFloat( dest )) ? true
307 : assignable;
308 }
309 if( src == Float.TYPE || Float.class.isAssignableFrom( src ) ){
310 assignable = (isByte( dest ) || isShort( dest ) || isInteger( dest ) || isLong( dest )) ? true
311 : assignable;
312 }
313 if( src == Long.TYPE || Long.class.isAssignableFrom( src ) ){
314 assignable = (isByte( dest ) || isShort( dest ) || isInteger( dest )) ? true : assignable;
315 }
316 if( src == Integer.TYPE || Integer.class.isAssignableFrom( src ) ){
317 assignable = (isByte( dest ) || isShort( dest )) ? true : assignable;
318 }
319 if( src == Short.TYPE || Short.class.isAssignableFrom( src ) ){
320 assignable = (isByte( dest )) ? true : assignable;
321 }
322
323 return assignable;
324 }
325
326 private boolean isByte( Class clazz )
327 {
328 return Byte.class.isAssignableFrom( clazz ) || clazz == Byte.TYPE;
329 }
330
331 private boolean isFloat( Class clazz )
332 {
333 return Float.class.isAssignableFrom( clazz ) || clazz == Float.TYPE;
334 }
335
336 private boolean isInteger( Class clazz )
337 {
338 return Integer.class.isAssignableFrom( clazz ) || clazz == Integer.TYPE;
339 }
340
341 private boolean isLong( Class clazz )
342 {
343 return Long.class.isAssignableFrom( clazz ) || clazz == Long.TYPE;
344 }
345
346 private boolean isShort( Class clazz )
347 {
348 return Short.class.isAssignableFrom( clazz ) || clazz == Short.TYPE;
349 }
350 }