static

in cayenne/src/main/java/org/apache/cayenne/exp/parser/Evaluator.java [79:292]


    static {
        evaluators = new ConcurrentHashMap<>();

        NULL_LHS_EVALUATOR = new Evaluator() {
            @Override
            Integer compare(Object lhs, Object rhs) {
                return null;
            }

            @Override
            boolean eq(Object lhs, Object rhs) {
                return rhs == null;
            }
        };

        DEFAULT_EVALUATOR = new NonNullLhsEvaluator(new Evaluator() {
            @Override
            boolean eq(Object lhs, Object rhs) {
                return lhs.equals(rhs);
            }

            @Override
            Integer compare(Object lhs, Object rhs) {
                return null;
            }
        });

        PERSISTENT_EVALUATOR = new NonNullLhsEvaluator(new Evaluator() {

            @Override
            Integer compare(Object lhs, Object rhs) {
                return null;
            }

            @Override
            boolean eq(Object lhs, Object rhs) {

                Persistent lhsPersistent = (Persistent) lhs;

                if (rhs instanceof Persistent) {
                    return lhsPersistent.getObjectId().equals(((Persistent) rhs).getObjectId());
                }

                if (rhs instanceof ObjectId) {
                    return lhsPersistent.getObjectId().equals(rhs);
                }

                if (rhs instanceof Map) {
                    return lhsPersistent.getObjectId().getIdSnapshot().equals(rhs);
                }

                if (lhsPersistent.getObjectId().getIdSnapshot().size() != 1) {
                    // the only options left below are for the single key IDs
                    return false;
                }

                if (rhs instanceof Number) {

                    // only care about whole numbers
                    if (rhs instanceof Integer) {
                        return Cayenne.longPKForObject(lhsPersistent) == ((Number) rhs).longValue();
                    }

                    if (rhs instanceof Long) {
                        return Cayenne.longPKForObject(lhsPersistent) == ((Number) rhs).longValue();
                    }
                }

                return Cayenne.pkForObject(lhsPersistent).equals(rhs);
            }
        });

        BIG_DECIMAL_EVALUATOR = new NonNullLhsEvaluator(new Evaluator() {

            @Override
            Integer compare(Object lhs, Object rhs) {
                return ((BigDecimal) lhs).compareTo(ConversionUtil.toBigDecimal(rhs));
            }

            @Override
            boolean eq(Object lhs, Object rhs) {
                // BigDecimals must be compared using compareTo (see CAY-280 and BigDecimal.equals JavaDoc)
                Integer c = compare(lhs, rhs);
                return c == 0;
            }
        });

        NUMBER_EVALUATOR = new NonNullLhsEvaluator(new Evaluator() {

            @SuppressWarnings({ "unchecked", "rawtypes" })
            @Override
            Integer compare(Object lhs, Object rhs) {
                return compareNumbers((Number)lhs, rhs);
            }

            @Override
            boolean eq(Object lhs, Object rhs) {
                return equalNumbers((Number)lhs, rhs);
            }
            
            private final List WHOLE_NUMBER_CLASSES = Arrays.asList(Byte.class, Short.class, Integer.class, AtomicInteger.class, Long.class, AtomicLong.class, BigInteger.class);

            /**
             * Returns the widest primitive wrapper class given the two operands, used in preparation for 
             * comparing two boxed numbers of different types, like java.lang.Short and java.lang.Integer.
             */
            Class<?> widestNumberType(Number lhs, Number rhs) {
            	if (lhs.getClass().equals(rhs.getClass())) return lhs.getClass();
            	
            	int lhsIndex = WHOLE_NUMBER_CLASSES.indexOf(lhs.getClass());
            	int rhsIndex = WHOLE_NUMBER_CLASSES.indexOf(rhs.getClass());

            	Class<?> widestClass;
            	if (lhsIndex != -1 && rhsIndex != -1) {
            		widestClass = (Class<?>) WHOLE_NUMBER_CLASSES.get(Math.max(lhsIndex, rhsIndex));
            	} else {
            		widestClass = Double.class;
            	}
            	
            	return widestClass;
            }
            
            /**
             * Enables equality tests for two boxed numbers of different types, like java.lang.Short and java.lang.Integer.
             */
            boolean equalNumbers(Number lhs, Object _rhs) {
            	if (!Number.class.isAssignableFrom(_rhs.getClass())) {
            		return lhs.equals(_rhs);
            	}
            	
            	Number rhs = (Number) _rhs;
            	
            	Class<?> widestClass = widestNumberType(lhs, rhs);
            	
            	if (Integer.class.equals(widestClass) || AtomicInteger.class.equals(widestClass)) {
            		return lhs.intValue() == rhs.intValue();
            		
            	} else if (Long.class.equals(widestClass) || AtomicLong.class.equals(widestClass)) {
            		return lhs.longValue() == rhs.longValue();
            		
            	} else if (Double.class.equals(widestClass)) {
            		return Math.abs(lhs.doubleValue() - rhs.doubleValue()) < EPSILON;
            		
            	} else if (Short.class.equals(widestClass)) {
                	return lhs.shortValue() == rhs.shortValue();
                	
            	} else if (BigInteger.class.equals(widestClass)) {
            		return lhs.toString().equals(rhs.toString());
            		
            	} else {
            		return lhs.equals(rhs);
            	}
            }
            
            /**
             * Enables comparison of two boxed numbers of different types, like java.lang.Short and java.lang.Integer.
             */
            Integer compareNumbers(Number lhs, Object _rhs) {
            	if (!Number.class.isAssignableFrom(_rhs.getClass())) {
            		return null;
            	}
            	
            	Number rhs = (Number) _rhs;
            	
            	Class widestClass = widestNumberType(lhs, rhs);
            	
            	if (Integer.class.equals(widestClass) || AtomicInteger.class.equals(widestClass)) {
            		return Integer.valueOf(lhs.intValue()).compareTo(rhs.intValue());
            		
            	} else if (Long.class.equals(widestClass) || AtomicLong.class.equals(widestClass)) {
            		return Long.valueOf(lhs.longValue()).compareTo(rhs.longValue());
            		
            	} else if (Double.class.equals(widestClass)) {
            		boolean areEqual = Math.abs(lhs.doubleValue() - rhs.doubleValue()) < EPSILON;
            		return areEqual ? 0 : Double.compare(lhs.doubleValue(), rhs.doubleValue());
            		
            	} else if (Float.class.equals(widestClass)) {
            		boolean areEqual = Math.abs(lhs.floatValue() - rhs.floatValue()) < EPSILON;
            		return areEqual ? 0 : Float.compare(lhs.floatValue(), rhs.floatValue());
            		
            	} else if (Short.class.equals(widestClass)) {
                	return Short.valueOf(lhs.shortValue()).compareTo(rhs.shortValue());
                	
            	} else if (Byte.class.equals(widestClass)) {
                	return Byte.valueOf(lhs.byteValue()).compareTo(rhs.byteValue());
                	
            	} else if (BigInteger.class.equals(widestClass)) {
            		BigInteger left = lhs instanceof BigInteger ? (BigInteger)lhs : new BigInteger(lhs.toString());
            		BigInteger right = rhs instanceof BigInteger ? (BigInteger)rhs : new BigInteger(rhs.toString());
            		return left.compareTo(right);
            		
            	} else if (Comparable.class.isAssignableFrom(lhs.getClass())) {
                    return ((Comparable)lhs).compareTo(rhs);
                    
                } else {
            		return null;
            	}
            }
        });
        
        COMPARABLE_EVALUATOR = new NonNullLhsEvaluator(new Evaluator() {

            @SuppressWarnings({ "unchecked", "rawtypes" })
            @Override
            Integer compare(Object lhs, Object rhs) {
                return ((Comparable) lhs).compareTo(ConversionUtil.toComparable(rhs));
            }

            @Override
            boolean eq(Object lhs, Object rhs) {
                return lhs.equals(rhs);
            }
        });
    }