1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krms.framework.engine.expression;
17
18 import org.apache.commons.lang.ObjectUtils;
19 import org.kuali.rice.krms.api.engine.IncompatibleTypeException;
20
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.InvocationTargetException;
23 import java.math.BigDecimal;
24 import java.math.BigInteger;
25
26
27
28
29
30
31
32
33
34 public class DefaultComparisonOperator implements EngineComparatorExtension, StringCoercionExtension {
35
36 @Override
37 public int compare(Object lhs, Object rhs) {
38
39 if (lhs == null && rhs == null) {
40 return 0;
41 } else if (lhs == null) {
42 return -1;
43 } else if (rhs == null) {
44 return 1;
45 }
46
47 rhs = coerceRhs(lhs, rhs);
48 if (ObjectUtils.equals(lhs, rhs)) {
49 return 0;
50 }
51
52 if (lhs instanceof Comparable && rhs instanceof Comparable) {
53 int result = ((Comparable)lhs).compareTo(rhs);
54 return result;
55 }
56 else {
57 throw new IncompatibleTypeException("DefaultComparisonOperator could not compare values", lhs, rhs.getClass());
58 }
59 }
60
61 @Override
62 public boolean canCompare(Object lhs, Object rhs) {
63 try {
64 compare(lhs, rhs);
65 return true;
66 } catch (Exception e) {
67 return false;
68 }
69 }
70
71
72
73
74
75
76
77
78 private Object coerceRhs(Object lhs, Object rhs) {
79 if (lhs != null && rhs != null) {
80 if (!lhs.getClass().equals(rhs.getClass()) && rhs instanceof String) {
81 rhs = coerceRhsHelper(lhs, rhs.toString(), Double.class, Float.class, Long.class, Integer.class);
82
83 if (rhs instanceof String) {
84 if (lhs instanceof BigDecimal) {
85 try {
86 rhs = BigDecimal.valueOf(Double.valueOf(rhs.toString()));
87 } catch (NumberFormatException e) {
88 throw new IncompatibleTypeException("Could not coerce String to BigDecimal" + this, rhs, lhs.getClass());
89 }
90 } else if (lhs instanceof BigInteger) {
91 try {
92 rhs = BigInteger.valueOf(Long.valueOf(rhs.toString()));
93 } catch (NumberFormatException e) {
94 throw new IncompatibleTypeException("Could not coerce String to BigInteger" + this, rhs, lhs.getClass());
95 }
96 } else {
97 throw new IncompatibleTypeException("Could not compare values for operator " + this, lhs, rhs.getClass());
98 }
99 }
100 }
101 }
102 return rhs;
103 }
104
105
106
107
108
109
110
111
112 private Object coerceRhsHelper(Object lhs, String rhs, Class<?> ... clazzes) {
113 for (Class clazz : clazzes) {
114 if (clazz.isInstance(lhs)) {
115 try {
116 return clazz.getMethod("valueOf", String.class).invoke(null, rhs);
117 } catch (NumberFormatException e) {
118 throw new IncompatibleTypeException("Could not coerce String to " +
119 clazz.getSimpleName() + " " + this, rhs, lhs.getClass());
120 } catch (NoSuchMethodException e) {
121 throw new IncompatibleTypeException("Could not coerce String to " +
122 clazz.getSimpleName() + " " + this, rhs, lhs.getClass());
123 } catch (InvocationTargetException e) {
124 throw new IncompatibleTypeException("Could not coerce String to " +
125 clazz.getSimpleName() + " " + this, rhs, lhs.getClass());
126 } catch (IllegalAccessException e) {
127 throw new IncompatibleTypeException("Could not coerce String to " +
128 clazz.getSimpleName() + " " + this, rhs, lhs.getClass());
129 }
130 }
131 }
132 return rhs;
133 }
134
135 @Override
136 public Object coerce(String type, String value) {
137 try {
138 Class clazz = Class.forName(type);
139
140 Constructor constructor = clazz.getConstructor(new Class[]{String.class});
141 Object propObject = constructor.newInstance(value);
142 return propObject;
143 } catch (Exception e) {
144 return null;
145 }
146 }
147
148 @Override
149 public boolean canCoerce(String type, String value) {
150 return coerce(type, value) != null;
151 }
152 }