-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCommonComparator.java
More file actions
166 lines (149 loc) · 4.44 KB
/
CommonComparator.java
File metadata and controls
166 lines (149 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package com.saviynt.pam.util;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Comparator;
import java.util.Date;
import java.util.Objects;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.saviynt.pam.enums.SortOrder;
import com.saviynt.pam.exception.BadRequestException;
/**
* The {@link CommonComparator} implements the generic comparator for
* all POJO classes using Reflection API
*/
public class CommonComparator<T> implements Comparator<T> {
private static final Logger log = LoggerFactory.getLogger(CommonComparator.class);
private static final String DATATYPE_STRING = "java.lang.String";
private static final String DATATYPE_DATE = "java.util.Date";
private static final String DATATYPE_INTEGER = "java.lang.Integer";
private static final String DATATYPE_LONG = "java.lang.Long";
private static final String DATATYPE_FLOAT = "java.lang.Float";
private static final String DATATYPE_DOUBLE = "java.lang.Double";
private static final String DATATYPE_SQL_TIMESTAMP = "java.sql.Timestamp";
private final String fieldName;
private final boolean isAscendingOrder;
private boolean isNullFirst;
public CommonComparator(final String fieldName, SortOrder sortOrder) {
this.fieldName = fieldName;
this.isAscendingOrder = SortOrder.asc == sortOrder;
}
public CommonComparator(final String fieldName, SortOrder sortOrder, boolean isNullFirst) {
this(fieldName,sortOrder);
this.isNullFirst = isNullFirst;
}
/**
* Override method for comparison of two elements(Objects).
*
* @param t1
* @param t2
* @return value
*
* @throws BadRequestException
*/
@Override
public int compare(final T t1, final T t2) {
try {
int value;
Object fieldVal1 = invokeGetterValue(t1);
Object fieldVal2 = invokeGetterValue(t2);
if (fieldVal1 == null || fieldVal2 == null) {
value = compareNull(fieldVal1, fieldVal2);
} else {
value = compareValue(fieldVal1, fieldVal2);
}
return value * determineOrder();
} catch (SecurityException | IllegalArgumentException e) {
log.error(ExceptionUtils.getStackTrace(e));
throw new BadRequestException("Invalid sort column");
}
}
/**
* Get actual value for the field
*
* @param t
* @return value
*
* @throws BadRequestException
*/
private Object invokeGetterValue(T t) {
Objects.requireNonNull(fieldName);
try {
PropertyDescriptor pd = new PropertyDescriptor(fieldName, t.getClass());
Method getter = pd.getReadMethod();
return getter.invoke(t);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
| IntrospectionException e) {
log.error(ExceptionUtils.getStackTrace(e));
throw new IllegalArgumentException("Invalid property");
}
}
/**
* Compare two actual values, according to different data types.
*
* @param v1
* @param v2
* @return -1,0,1
*/
private int compareNull(final Object v1, final Object v2) {
int actual = -1;
if (v1 == null && v2 == null)
actual = 0;
else if(v1 == null)
actual = 1;
return actual * determineNullPos() * determineOrder();
}
/**
* Compare two actual values, according to different data types.
*
* @param v1
* @param v2
* @return -1,0,1
*/
private int compareValue(final Object v1, final Object v2) {
int actual;
switch (v1.getClass().getName()) {
case DATATYPE_INTEGER:
actual = ((Integer) v1).compareTo((Integer) v2);
break;
case DATATYPE_LONG:
actual = ((Long) v1).compareTo((Long) v2);
break;
case DATATYPE_STRING:
actual = ((String) v1).compareTo((String) v2);
break;
case DATATYPE_DATE:
actual = ((Date) v1).compareTo((Date) v2);
break;
case DATATYPE_FLOAT:
actual = ((Float) v1).compareTo((Float) v2);
break;
case DATATYPE_DOUBLE:
actual = ((Double) v1).compareTo((Double) v2);
break;
case DATATYPE_SQL_TIMESTAMP:
actual = ((Timestamp) v1).compareTo((Timestamp) v2);
break;
default:
log.error("Unsupported data type {}",v1.getClass().getName());
throw new IllegalArgumentException("Unsupported data type");
}
return actual;
}
/**
* Get order type
*/
private int determineOrder() {
return isAscendingOrder ? 1 : -1;
}
/**
* Get null order type
*/
private int determineNullPos() {
return isNullFirst ? -1 : 1;
}
}