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.util.Arrays;
21 import java.util.Comparator;
22 import java.util.HashMap;
23 import java.util.Iterator;
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
37
38
39
40 public final class MorphDynaClass implements DynaClass, Serializable
41 {
42 private static final Comparator dynaPropertyComparator = new Comparator(){
43 public int compare( Object a, Object b )
44 {
45 if( a instanceof DynaProperty && b instanceof DynaProperty ){
46 DynaProperty p1 = (DynaProperty) a;
47 DynaProperty p2 = (DynaProperty) b;
48 return p1.getName()
49 .compareTo( p2.getName() );
50 }
51 return -1;
52 }
53 };
54
55 private static final long serialVersionUID = -613214016860871560L;
56
57 private Map attributes;
58 private Class beanClass;
59 private DynaProperty dynaProperties[];
60 private String name;
61 private Map properties = new HashMap();
62 private Class type;
63
64 public MorphDynaClass( Map attributes )
65 {
66 this( null, null, attributes );
67 }
68
69 public MorphDynaClass( Map attributes, boolean exceptionOnEmptyAttributes )
70 {
71 this( null, null, attributes, exceptionOnEmptyAttributes );
72 }
73
74 public MorphDynaClass( String name, Class type, Map attributes )
75 {
76 this( name, type, attributes, false );
77 }
78
79 public MorphDynaClass( String name, Class type, Map attributes,
80 boolean exceptionOnEmptyAttributes )
81 {
82 if( name == null ){
83 name = "MorphDynaClass";
84 }
85 if( type == null ){
86 type = MorphDynaBean.class;
87 }
88 if( !MorphDynaBean.class.isAssignableFrom( type ) ){
89 throw new MorphException( "MorphDynaBean is not assignable from " + type.getName() );
90 }
91 if( attributes == null || attributes.isEmpty() ){
92 if( exceptionOnEmptyAttributes ){
93 throw new MorphException( "Attributes map is null or empty." );
94 }else{
95 attributes = new HashMap();
96 }
97 }
98 this.name = name;
99 this.type = type;
100 this.attributes = attributes;
101 process();
102 }
103
104 public boolean equals( Object obj )
105 {
106 if( this == obj ){
107 return true;
108 }
109
110 if( obj == null ){
111 return false;
112 }
113
114 if( !(obj instanceof MorphDynaClass) ){
115 return false;
116 }
117
118 MorphDynaClass other = (MorphDynaClass) obj;
119 EqualsBuilder builder = new EqualsBuilder().append( this.name, other.name )
120 .append( this.type, other.type );
121 if( dynaProperties.length != other.dynaProperties.length ){
122 return false;
123 }
124 for( int i = 0; i < dynaProperties.length; i++ ){
125 DynaProperty a = this.dynaProperties[i];
126 DynaProperty b = other.dynaProperties[i];
127 builder.append( a.getName(), b.getName() );
128 builder.append( a.getType(), b.getType() );
129 }
130 return builder.isEquals();
131 }
132
133 public DynaProperty[] getDynaProperties()
134 {
135 return dynaProperties;
136 }
137
138 public DynaProperty getDynaProperty( String propertyName )
139 {
140 if( propertyName == null ){
141 throw new MorphException( "Unnespecified bean property name" );
142
143 }
144 return (DynaProperty) properties.get( propertyName );
145 }
146
147 public String getName()
148 {
149 return this.name;
150 }
151
152 public int hashCode()
153 {
154 HashCodeBuilder builder = new HashCodeBuilder().append( name )
155 .append( type );
156 for( int i = 0; i < dynaProperties.length; i++ ){
157 builder.append( this.dynaProperties[i].getName() );
158 builder.append( this.dynaProperties[i].getType() );
159 }
160 return builder.toHashCode();
161 }
162
163 public DynaBean newInstance() throws IllegalAccessException, InstantiationException
164 {
165 return newInstance( null );
166 }
167
168 public DynaBean newInstance( MorpherRegistry morpherRegistry ) throws IllegalAccessException,
169 InstantiationException
170 {
171 if( morpherRegistry == null ){
172 morpherRegistry = new MorpherRegistry();
173 MorphUtils.registerStandardMorphers( morpherRegistry );
174 }
175 MorphDynaBean dynaBean = (MorphDynaBean) getBeanClass().newInstance();
176 dynaBean.setDynaBeanClass( this );
177 dynaBean.setMorpherRegistry( morpherRegistry );
178 Iterator keys = attributes.keySet()
179 .iterator();
180 while( keys.hasNext() ){
181 String key = (String) keys.next();
182 dynaBean.set( key, null );
183 }
184 return dynaBean;
185 }
186
187 public String toString()
188 {
189 return new ToStringBuilder( this ).append( "name", this.name )
190 .append( "type", this.type )
191 .append( "attributes", this.attributes )
192 .toString();
193 }
194
195 protected Class getBeanClass()
196 {
197 if( this.beanClass == null ){
198 process();
199 }
200 return this.beanClass;
201 }
202
203 private void process()
204 {
205 this.beanClass = this.type;
206
207 try{
208 Iterator entries = attributes.entrySet()
209 .iterator();
210 dynaProperties = new DynaProperty[attributes.size()];
211 int i = 0;
212 while( entries.hasNext() ){
213 Map.Entry entry = (Map.Entry) entries.next();
214 String pname = (String) entry.getKey();
215 Object pclass = entry.getValue();
216 DynaProperty dynaProperty = null;
217 if( pclass instanceof String ){
218 Class klass = (Class) Class.forName( (String) pclass );
219 if( klass.isArray() && klass.getComponentType()
220 .isArray() ){
221 throw new MorphException( "Multidimensional arrays are not supported" );
222 }
223 dynaProperty = new DynaProperty( pname, klass );
224 }else if( pclass instanceof Class ){
225 Class klass = (Class) pclass;
226 if( klass.isArray() && klass.getComponentType()
227 .isArray() ){
228 throw new MorphException( "Multidimensional arrays are not supported" );
229 }
230 dynaProperty = new DynaProperty( pname, klass );
231 }else{
232 throw new MorphException( "Type must be String or Class" );
233 }
234 properties.put( dynaProperty.getName(), dynaProperty );
235 dynaProperties[i++] = dynaProperty;
236 }
237 }
238 catch( ClassNotFoundException cnfe ){
239 throw new MorphException( cnfe );
240 }
241
242
243 Arrays.sort( dynaProperties, 0, dynaProperties.length, dynaPropertyComparator );
244 }
245 }