1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
package net.sf.beanform.prop; |
16 |
|
|
17 |
|
import java.beans.PropertyDescriptor; |
18 |
|
import java.io.Serializable; |
19 |
|
import java.lang.annotation.Annotation; |
20 |
|
import java.lang.reflect.Field; |
21 |
|
import java.lang.reflect.InvocationTargetException; |
22 |
|
import java.util.ArrayList; |
23 |
|
import java.util.Arrays; |
24 |
|
import java.util.Date; |
25 |
|
import java.util.List; |
26 |
|
|
27 |
|
import net.sf.beanform.integration.IntegratorChain; |
28 |
|
import net.sf.beanform.util.ReflectionUtils; |
29 |
|
|
30 |
|
import org.apache.commons.logging.Log; |
31 |
|
import org.apache.commons.logging.LogFactory; |
32 |
|
import org.apache.hivemind.ApplicationRuntimeException; |
33 |
|
import org.apache.hivemind.util.Defense; |
34 |
|
|
35 |
|
|
36 |
|
|
37 |
|
|
38 |
|
|
39 |
|
|
40 |
|
|
41 |
|
|
42 |
|
|
43 |
|
|
44 |
|
|
45 |
|
public class BeanProperty implements Serializable { |
46 |
|
|
47 |
|
private static final long serialVersionUID = -9064407627959060313L; |
48 |
|
|
49 |
1 |
private static final Log LOG = LogFactory.getLog( BeanProperty.class ); |
50 |
1 |
private static final Annotation[] EMPTY = new Annotation[ 0 ]; |
51 |
|
|
52 |
1 |
private static final String STRING = String.class.getName(); |
53 |
1 |
private static final String BOOLEAN = Boolean.class.getName(); |
54 |
1 |
private static final String BOOL = boolean.class.getName(); |
55 |
1 |
private static final String SHORT = Short.class.getName(); |
56 |
1 |
private static final String SRT = short.class.getName(); |
57 |
1 |
private static final String INTEGER = Integer.class.getName(); |
58 |
1 |
private static final String INT = int.class.getName(); |
59 |
1 |
private static final String LONG = Long.class.getName(); |
60 |
1 |
private static final String LNG = long.class.getName(); |
61 |
1 |
private static final String FLOAT = Float.class.getName(); |
62 |
1 |
private static final String FLT = float.class.getName(); |
63 |
1 |
private static final String DOUBLE = Double.class.getName(); |
64 |
1 |
private static final String DBL = double.class.getName(); |
65 |
1 |
private static final String DATE = Date.class.getName(); |
66 |
1 |
private static final String BYTE_ARRAY = byte[].class.getName(); |
67 |
|
|
68 |
|
private final static String INPUT_TEXTFIELD = "TextField"; |
69 |
|
private final static String INPUT_TEXTAREA = "TextArea"; |
70 |
|
private final static String INPUT_CHECKBOX = "Checkbox"; |
71 |
|
private final static String INPUT_DATEPICKER = "DatePicker"; |
72 |
|
private final static String INPUT_UPLOAD = "Upload"; |
73 |
|
private final static String INPUT_INSERT = "Insert"; |
74 |
|
|
75 |
1 |
private final static List<String> INPUTS = Arrays.asList( |
76 |
|
INPUT_TEXTFIELD, |
77 |
|
INPUT_TEXTAREA, |
78 |
|
INPUT_CHECKBOX, |
79 |
|
INPUT_DATEPICKER, |
80 |
|
INPUT_UPLOAD, |
81 |
|
INPUT_INSERT |
82 |
|
); |
83 |
|
|
84 |
|
private final Class ownerClass; |
85 |
|
private final String name; |
86 |
|
private final String[] names; |
87 |
|
private final String validators; |
88 |
|
private final String input; |
89 |
|
|
90 |
|
private transient PropertyDescriptor descriptor; |
91 |
|
private transient Field field; |
92 |
|
|
93 |
214 |
public BeanProperty( Class ownerClass, String name, String validators, String input ) { |
94 |
|
|
95 |
214 |
Defense.notNull( ownerClass, "ownerClass" ); |
96 |
213 |
Defense.notNull( name, "name" ); |
97 |
|
|
98 |
212 |
this.ownerClass = ownerClass; |
99 |
212 |
this.name = name; |
100 |
212 |
this.names = name.split( "\\." ); |
101 |
|
|
102 |
212 |
if( validators != null ) this.validators = validators; |
103 |
174 |
else this.validators = IntegratorChain.getValidation( this ); |
104 |
|
|
105 |
212 |
if( input != null ) this.input = input; |
106 |
164 |
else this.input = this.inferInputFromType(); |
107 |
|
|
108 |
212 |
if( (!this.usesTextField()) && (!this.usesTextArea()) && (!this.usesCheckbox()) && |
109 |
|
(!this.usesDatePicker()) && (!this.usesUpload()) && (!this.usesInsert()) ) { |
110 |
1 |
String msg = BeanPropertyMessages.unrecognizedInputType( this, INPUTS ); |
111 |
1 |
throw new ApplicationRuntimeException( msg ); |
112 |
|
} |
113 |
211 |
} |
114 |
|
|
115 |
|
private String inferInputFromType() { |
116 |
164 |
if( this.isShortString() || this.isNumber() ) return INPUT_TEXTFIELD; |
117 |
74 |
else if( this.isLongString() ) return INPUT_TEXTAREA; |
118 |
67 |
else if( this.isBoolean() ) return INPUT_CHECKBOX; |
119 |
49 |
else if( this.isDate() ) return INPUT_DATEPICKER; |
120 |
41 |
else if( this.isByteArray() ) return INPUT_UPLOAD; |
121 |
36 |
else return INPUT_INSERT; |
122 |
|
} |
123 |
|
|
124 |
|
private PropertyDescriptor getPropertyDescriptor() { |
125 |
3731 |
if( this.descriptor == null ) { |
126 |
190 |
this.descriptor = ReflectionUtils.getPropertyDescriptor( this.ownerClass, this.names ); |
127 |
|
} |
128 |
3731 |
return this.descriptor; |
129 |
|
} |
130 |
|
|
131 |
|
private Field getField() { |
132 |
4092 |
if( this.field == null ) { |
133 |
|
try { |
134 |
220 |
this.field = ReflectionUtils.getField( this.ownerClass, this.names ); |
135 |
|
} |
136 |
44 |
catch( NoSuchFieldException e ) { |
137 |
44 |
if( LOG.isDebugEnabled() ) { |
138 |
44 |
String msg = "The field '" + this.getName() + "' does not exist. "; |
139 |
44 |
msg += "Perhaps the field name does not match the property name?"; |
140 |
44 |
LOG.debug( msg ); |
141 |
|
} |
142 |
176 |
} |
143 |
|
} |
144 |
4092 |
return this.field; |
145 |
|
} |
146 |
|
|
147 |
|
public Class getOwnerClass() { |
148 |
13 |
return this.ownerClass; |
149 |
|
} |
150 |
|
|
151 |
|
public String getName() { |
152 |
317 |
return this.name; |
153 |
|
} |
154 |
|
|
155 |
|
public String getValidators() { |
156 |
68 |
return this.validators; |
157 |
|
} |
158 |
|
|
159 |
|
public String getInput() { |
160 |
55 |
return this.input; |
161 |
|
} |
162 |
|
|
163 |
|
public boolean usesTextField() { |
164 |
226 |
return INPUT_TEXTFIELD.equalsIgnoreCase( this.input ); |
165 |
|
} |
166 |
|
|
167 |
|
public boolean usesTextArea() { |
168 |
120 |
return INPUT_TEXTAREA.equalsIgnoreCase( this.input ); |
169 |
|
} |
170 |
|
|
171 |
|
public boolean usesCheckbox() { |
172 |
100 |
return INPUT_CHECKBOX.equalsIgnoreCase( this.input ); |
173 |
|
} |
174 |
|
|
175 |
|
public boolean usesDatePicker() { |
176 |
75 |
return INPUT_DATEPICKER.equalsIgnoreCase( this.input ); |
177 |
|
} |
178 |
|
|
179 |
|
public boolean usesUpload() { |
180 |
58 |
return INPUT_UPLOAD.equalsIgnoreCase( this.input ); |
181 |
|
} |
182 |
|
|
183 |
|
public boolean usesInsert() { |
184 |
54 |
return INPUT_INSERT.equalsIgnoreCase( this.input ); |
185 |
|
} |
186 |
|
|
187 |
|
public List<Annotation> getAnnotations() { |
188 |
2068 |
PropertyDescriptor pd = this.getPropertyDescriptor(); |
189 |
2068 |
Annotation[] a1 = ( pd.getReadMethod() == null ? EMPTY : pd.getReadMethod().getAnnotations() ); |
190 |
2068 |
Annotation[] a2 = ( pd.getWriteMethod() == null ? EMPTY : pd.getWriteMethod().getAnnotations() ); |
191 |
2068 |
Annotation[] a3 = ( this.getField() == null ? EMPTY : this.getField().getAnnotations() ); |
192 |
2068 |
List<Annotation> list = new ArrayList<Annotation>(); |
193 |
2068 |
list.addAll( Arrays.asList( a1 ) ); |
194 |
2068 |
list.addAll( Arrays.asList( a2 ) ); |
195 |
2068 |
list.addAll( Arrays.asList( a3 ) ); |
196 |
2068 |
return list; |
197 |
|
} |
198 |
|
|
199 |
|
@SuppressWarnings( "unchecked" ) |
200 |
|
public <T extends Annotation> T getAnnotation( Class<T> clazz ) { |
201 |
2098 |
Annotation result = null; |
202 |
2098 |
for( Annotation a : this.getAnnotations() ) { |
203 |
366 |
if( clazz.isAssignableFrom( a.getClass() ) ) { |
204 |
73 |
result = a; |
205 |
73 |
break; |
206 |
|
} |
207 |
293 |
} |
208 |
2098 |
return (T) result; |
209 |
|
} |
210 |
|
|
211 |
|
public boolean isReadable() { |
212 |
12 |
return this.getPropertyDescriptor().getReadMethod() != null; |
213 |
|
} |
214 |
|
|
215 |
|
public boolean isWriteable() { |
216 |
13 |
return this.getPropertyDescriptor().getWriteMethod() != null; |
217 |
|
} |
218 |
|
|
219 |
|
public boolean isNullable() { |
220 |
9 |
return IntegratorChain.isNullable( this ); |
221 |
|
} |
222 |
|
|
223 |
|
public Class getType() { |
224 |
1638 |
return this.getPropertyDescriptor().getPropertyType(); |
225 |
|
} |
226 |
|
|
227 |
|
public String getTypeName() { |
228 |
1571 |
Class type = this.getType(); |
229 |
1571 |
return ( type != null ? type.getName() : null ); |
230 |
|
} |
231 |
|
|
232 |
|
public boolean isEnum() { |
233 |
96 |
Class type = this.getType(); |
234 |
96 |
return ( type != null && type.isEnum() ); |
235 |
|
} |
236 |
|
|
237 |
|
public boolean isString() { |
238 |
381 |
String typeName = this.getTypeName(); |
239 |
381 |
return STRING.equals( typeName ); |
240 |
|
} |
241 |
|
|
242 |
|
public boolean isShortString() { |
243 |
192 |
if( this.isString() == false ) return false; |
244 |
72 |
Integer maxLength = IntegratorChain.getMaxLength( this ); |
245 |
72 |
if( maxLength == null ) return true; |
246 |
47 |
if( maxLength < 256 ) return true; |
247 |
20 |
return false; |
248 |
|
} |
249 |
|
|
250 |
|
public boolean isLongString() { |
251 |
87 |
return this.isString() && ! this.isShortString(); |
252 |
|
} |
253 |
|
|
254 |
|
public boolean isBoolean() { |
255 |
152 |
String typeName = this.getTypeName(); |
256 |
152 |
return BOOLEAN.equals( typeName ) || BOOL.equals( typeName ); |
257 |
|
} |
258 |
|
|
259 |
|
public boolean isShort() { |
260 |
220 |
String typeName = this.getTypeName(); |
261 |
220 |
return SHORT.equals( typeName ) || SRT.equals( typeName ); |
262 |
|
} |
263 |
|
|
264 |
|
public boolean isInteger() { |
265 |
191 |
String typeName = this.getTypeName(); |
266 |
191 |
return INTEGER.equals( typeName ) || INT.equals( typeName ); |
267 |
|
} |
268 |
|
|
269 |
|
public boolean isLong() { |
270 |
170 |
String typeName = this.getTypeName(); |
271 |
170 |
return LONG.equals( typeName ) || LNG.equals( typeName ); |
272 |
|
} |
273 |
|
|
274 |
|
public boolean isFloat() { |
275 |
160 |
String typeName = this.getTypeName(); |
276 |
160 |
return FLOAT.equals( typeName ) || FLT.equals( typeName ); |
277 |
|
} |
278 |
|
|
279 |
|
public boolean isDouble() { |
280 |
139 |
String typeName = this.getTypeName(); |
281 |
139 |
return DOUBLE.equals( typeName ) || DBL.equals( typeName ); |
282 |
|
} |
283 |
|
|
284 |
|
public boolean isNumber() { |
285 |
202 |
return this.isShort() || this.isInteger() || this.isLong() || this.isFloat() || this.isDouble(); |
286 |
|
} |
287 |
|
|
288 |
|
public boolean isDate() { |
289 |
84 |
String typeName = this.getTypeName(); |
290 |
84 |
return DATE.equals( typeName ); |
291 |
|
} |
292 |
|
|
293 |
|
public boolean isByteArray() { |
294 |
67 |
String typeName = this.getTypeName(); |
295 |
67 |
return BYTE_ARRAY.equals( typeName ); |
296 |
|
} |
297 |
|
|
298 |
|
public boolean isEditableType() { |
299 |
91 |
return this.isString() || this.isBoolean() || this.isNumber() || this.isDate() || this.isByteArray(); |
300 |
|
} |
301 |
|
|
302 |
|
@Override |
303 |
|
public String toString() { |
304 |
204 |
return this.name + |
305 |
|
( this.input != null ? "=" + this.input : "" ) + |
306 |
|
( this.validators != null ? "{" + this.validators + "}" : "" ); |
307 |
|
} |
308 |
|
|
309 |
|
|
310 |
|
|
311 |
|
|
312 |
|
|
313 |
|
@Override |
314 |
|
public boolean equals( Object o ) { |
315 |
29 |
if( o instanceof BeanProperty == false ) return false; |
316 |
29 |
BeanProperty prop = (BeanProperty) o; |
317 |
29 |
boolean c = ( this.ownerClass == null ? prop.ownerClass == null : this.ownerClass.equals( prop.ownerClass ) ); |
318 |
29 |
boolean n = ( this.name == null ? prop.name == null : this.name.equals( prop.name ) ); |
319 |
29 |
boolean v = ( this.validators == null ? prop.validators == null : this.validators.equals( prop.validators ) ); |
320 |
29 |
boolean i = ( this.input == null ? prop.input == null : this.input.equals( prop.input ) ); |
321 |
29 |
return c && n && v && i; |
322 |
|
} |
323 |
|
|
324 |
|
|
325 |
|
|
326 |
|
|
327 |
|
|
328 |
|
|
329 |
|
|
330 |
|
@Override |
331 |
|
public int hashCode() { |
332 |
130 |
int result = 17; |
333 |
130 |
result = ( this.ownerClass != null ? 37 * result + this.ownerClass.hashCode() : result * 37 ); |
334 |
130 |
result = ( this.name != null ? 37 * result + this.name.hashCode() : result * 37 ); |
335 |
130 |
result = ( this.validators != null ? 37 * result + this.validators.hashCode() : result * 37 ); |
336 |
130 |
result = ( this.input != null ? 37 * result + this.input.hashCode() : result * 37 ); |
337 |
130 |
return result; |
338 |
|
} |
339 |
|
|
340 |
|
|
341 |
|
|
342 |
|
|
343 |
|
|
344 |
|
private transient Object bean; |
345 |
|
|
346 |
|
public void setBean( Object bean ) { |
347 |
8 |
if( bean == null ) { |
348 |
1 |
LOG.warn( BeanPropertyMessages.setBeanNullBean() ); |
349 |
|
} |
350 |
8 |
this.bean = bean; |
351 |
8 |
} |
352 |
|
|
353 |
|
public Object getValue() { |
354 |
4 |
if( this.bean == null ) { |
355 |
1 |
String msg = BeanPropertyMessages.getValueNullBean(); |
356 |
1 |
throw new ApplicationRuntimeException( msg ); |
357 |
|
} |
358 |
3 |
if( this.isReadable() == false ) { |
359 |
1 |
String msg = BeanPropertyMessages.getValueNotReadable( this ); |
360 |
1 |
throw new ApplicationRuntimeException( msg ); |
361 |
|
} |
362 |
|
try { |
363 |
2 |
return ReflectionUtils.getPropertyValue( this.bean, this.names ); |
364 |
|
} |
365 |
0 |
catch( IllegalAccessException iae ) { |
366 |
0 |
throw new ApplicationRuntimeException( iae ); |
367 |
|
} |
368 |
0 |
catch( InvocationTargetException ite ) { |
369 |
0 |
throw new ApplicationRuntimeException( ite ); |
370 |
|
} |
371 |
|
finally { |
372 |
2 |
this.bean = null; |
373 |
2 |
} |
374 |
|
} |
375 |
|
|
376 |
|
public void setValue( Object value ) { |
377 |
4 |
if( this.bean == null ) { |
378 |
1 |
String msg = BeanPropertyMessages.setValueNullBean(); |
379 |
1 |
throw new ApplicationRuntimeException( msg ); |
380 |
|
} |
381 |
3 |
if( this.isWriteable() == false ) { |
382 |
1 |
String msg = BeanPropertyMessages.setValueNotWriteable( this ); |
383 |
1 |
throw new ApplicationRuntimeException( msg ); |
384 |
|
} |
385 |
|
try { |
386 |
2 |
ReflectionUtils.setPropertyValue( value, this.bean, this.names ); |
387 |
|
} |
388 |
0 |
catch( IllegalAccessException iae ) { |
389 |
0 |
throw new ApplicationRuntimeException( iae ); |
390 |
|
} |
391 |
0 |
catch( InvocationTargetException ite ) { |
392 |
0 |
throw new ApplicationRuntimeException( ite ); |
393 |
|
} |
394 |
0 |
catch( InstantiationException ie ) { |
395 |
0 |
throw new ApplicationRuntimeException( ie ); |
396 |
|
} |
397 |
0 |
catch( IllegalArgumentException iae ) { |
398 |
0 |
String msg = BeanPropertyMessages.setValueIllegalArgument( value ); |
399 |
0 |
throw new ApplicationRuntimeException( msg, iae ); |
400 |
|
} |
401 |
|
finally { |
402 |
2 |
this.bean = null; |
403 |
2 |
} |
404 |
2 |
} |
405 |
|
|
406 |
|
} |