com.feilong.core.util.comparator.PropertyComparator.java Source code

Java tutorial

Introduction

Here is the source code for com.feilong.core.util.comparator.PropertyComparator.java

Source

/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.core.util.comparator;

import java.io.Serializable;
import java.util.Comparator;

import org.apache.commons.collections4.comparators.ReverseComparator;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.feilong.core.bean.ConvertUtil;
import com.feilong.core.bean.PropertyUtil;

/**
 * ,? <code>T</code>?? {@link #propertyName},,???? {@link Comparator}.
 * 
 * <h3> {@link #propertyName}:</h3>
 * 
 * <blockquote>
 * <p>
 * {@link #propertyName} ??, {@link Comparable}?, {@link Integer}, {@link String}
 * </p>
 * </blockquote>
 * 
 * <h3>?:</h3>
 * 
 * <blockquote>
 * <p>
 * <span style="color:red">?</span>?,????,? {@link ReverseComparator}
 * </p>
 * </blockquote>
 *
 * @author <a href="http://feitianbenyue.iteye.com/">feilong</a>
 * @param <T>
 *            the generic type
 * @see org.apache.commons.collections4.ComparatorUtils
 * @see "org.springframework.beans.support.PropertyComparator"
 * @see org.apache.commons.beanutils.BeanComparator
 * @see org.apache.commons.collections4.comparators.BooleanComparator
 * @see org.apache.commons.collections4.comparators.ReverseComparator
 * @see org.apache.commons.collections4.comparators.ComparableComparator
 * @see <a href=
 *      "http://stackoverflow.com/questions/19325256/java-lang-illegalargumentexception-comparison-method-violates-its-general-contr">java-
 *      lang-illegalargumentexception-comparison-method-violates-its-general-contr</a>
 * @see <a href=
 *      "http://stackoverflow.com/questions/11441666/java-error-comparison-method-violates-its-general-contract">Java error: Comparison
 *      method violates its general contract</a>
 * @since 1.2.0
 */
public class PropertyComparator<T> implements Comparator<T>, Serializable {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = -3159374167882773300L;

    /** The Constant LOGGER. */
    private static final Logger LOGGER = LoggerFactory.getLogger(PropertyComparator.class);

    /**
     * T??,Possibly indexed and/or nested name of the property to be modified,??
     * <a href="../../bean/BeanUtil.html#propertyName">propertyName</a>,value  {@link Comparable}?.
     */
    private final String propertyName;

    /** The comparator. */
    @SuppressWarnings("rawtypes")
    private Comparator comparator;

    /** ??????,??. */
    @SuppressWarnings("rawtypes")
    private Class<? extends Comparable> propertyValueConvertToClass;

    /**
     * The Constructor.
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * List{@code <User>} list = new ArrayList{@code <User>}();
     * list.add(new User(12L, 18));
     * list.add(new User(2L, 36));
     * list.add(new User(5L, 22));
     * list.add(new User(1L, 8));
     * 
     * Collections.sort(list, new PropertyComparator{@code <User>}("id"));
     * LOGGER.debug(JsonUtil.format(list));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
    [{
            "id": 1,
            "age": 8
        },
                {
            "id": 2,
            "age": 36
        },
                {
            "id": 5,
            "age": 22
        },
                {
            "id": 12,
            "age": 18
    }]
     * </pre>
     * 
     * </blockquote>
     *
     * @param propertyName
     *            T??,value  {@link Comparable}?.
     */
    public PropertyComparator(String propertyName) {
        Validate.notBlank(propertyName, "propertyName can't be blank!");
        this.propertyName = propertyName;
        LOGGER.trace("propertyName:[{}]", propertyName);
    }

    /**
     * The Constructor.
     *
     * @param propertyName
     *            the property name
     * @param comparator
     *            the comparator
     * @since 1.5.4
     */
    @SuppressWarnings("rawtypes")
    public PropertyComparator(String propertyName, Comparator comparator) {
        Validate.notBlank(propertyName, "propertyName can't be blank!");
        this.propertyName = propertyName;
        this.comparator = comparator;
        LOGGER.trace("propertyName:[{}]", propertyName);
    }

    /**
     * The Constructor.
     * 
     * <h3>:</h3>
     * <blockquote>
     * ??,??,<br>
     * ??,??Integer?,13  3??
     * </blockquote>
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * <p>
     * ?, totalNo
     * </p>
     * 
     * <pre class="code">
     * CourseEntity courseEntity1 = new CourseEntity();
     * courseEntity1.setTotalNo("3");
     * 
     * CourseEntity courseEntity2 = new CourseEntity();
     * courseEntity2.setTotalNo("13");
     * 
     * List{@code <CourseEntity>} courseList = new ArrayList{@code <>}();
     * courseList.add(courseEntity1);
     * courseList.add(courseEntity2);
     * </pre>
     * 
     *  ? propertyName??:
     * 
     * <pre class="code">
     * Collections.sort(courseList, new PropertyComparator{@code <CourseEntity>}("totalNo"));
     * LOGGER.debug(JsonUtil.format(courseList));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * [{
     * "totalNo": "13",
     * "name": ""
     * },{
     * "totalNo": "3",
     * "name": ""
     * }]
     * </pre>
     * 
     *  propertyName+ propertyValueConvertToClass??:
     * 
     * <pre class="code">
     * Collections.sort(courseList, new PropertyComparator{@code <CourseEntity>}("totalNo", Integer.class));
     * LOGGER.debug(JsonUtil.format(courseList));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * [{
     * "totalNo": "3",
     * "name": ""
     * },{
     * "totalNo": "13",
     * "name": ""
     * }]
     * </pre>
     * 
     * </blockquote>
     *
     * @param propertyName
     *            T??,Possibly indexed and/or nested name of the property to be modified,??
     *            <a href="../../bean/BeanUtil.html#propertyName">propertyName</a>,value  {@link Comparable}?.
     * @param propertyValueConvertToClass
     *            ??????,??
     * @since 1.5.0
     */
    @SuppressWarnings("rawtypes")
    public PropertyComparator(String propertyName, Class<? extends Comparable> propertyValueConvertToClass) {
        Validate.notBlank(propertyName, "propertyName can't be blank!");
        this.propertyName = propertyName;
        this.propertyValueConvertToClass = propertyValueConvertToClass;
        LOGGER.trace("propertyName:[{}]", propertyName);
    }

    /**
     * The Constructor.
     * *
     * <h3>:</h3>
     * <blockquote>
     * ??,??,<br>
     * ??,??Integer?,13  3??
     * </blockquote>
     *
     * @param propertyName
     *            T??,Possibly indexed and/or nested name of the property to be modified,??
     *            <a href="../../bean/BeanUtil.html#propertyName">propertyName</a>,value  {@link Comparable}?.
     * @param propertyValueConvertToClass
     *            ??????,??
     * @param comparator
     *            the comparator
     * @since 1.5.4
     */
    @SuppressWarnings("rawtypes")
    public PropertyComparator(String propertyName, Class<? extends Comparable> propertyValueConvertToClass,
            Comparator comparator) {
        Validate.notBlank(propertyName, "propertyName can't be blank!");
        this.propertyName = propertyName;
        this.propertyValueConvertToClass = propertyValueConvertToClass;
        this.comparator = comparator;
        LOGGER.trace("propertyName:[{}]", propertyName);
    }

    /**
     * Compare.
     *
     * @param t1
     *            the t1
     * @param t2
     *            the t2
     * @return the int
     * @see org.apache.commons.lang3.ObjectUtils#compare(Comparable, Comparable)
     * @see org.apache.commons.lang3.ObjectUtils#compare(Comparable, Comparable, boolean)
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public int compare(T t1, T t2) {
        if (t1 == t2) {
            return 0;
        } else if (null == t1) {//null ??
            return 1;
        } else if (null == t2) {
            return -1;
        }

        Comparable propertyValue1 = PropertyUtil.getProperty(t1, propertyName);
        Comparable propertyValue2 = PropertyUtil.getProperty(t2, propertyName);

        //??
        if (null != propertyValueConvertToClass) {
            propertyValue1 = ConvertUtil.convert(propertyValue1, propertyValueConvertToClass);
            propertyValue2 = ConvertUtil.convert(propertyValue2, propertyValueConvertToClass);
        }
        return null != comparator ? comparator.compare(propertyValue1, propertyValue2)
                : compare(t1, t2, propertyValue1, propertyValue2);
    }

    /**
     *  propertyValue1?propertyValue2,? t1/t2 .
     * 
     * <p>
     * ??? property, ??,  TreeSet / TreeMap ?sort??
     * </p>
     *
     * @param t1
     *            the t1
     * @param t2
     *            the t2
     * @param propertyValue1
     *            the property value1
     * @param propertyValue2
     *            the property value2
     * @return the int
     * @see org.apache.commons.collections4.comparators.ComparableComparator
     * @since 1.5.4
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private int compare(T t1, T t2, Comparable propertyValue1, Comparable propertyValue2) {
        //NullPointException if propertyValue1.compareTo(propertyValue2);
        int compareTo = ObjectUtils.compare(propertyValue1, propertyValue2);

        if (0 == compareTo) {
            //??TreeSet / TreeMap ?sort??
            int hashCode1 = t1.hashCode();
            int hashCode2 = t2.hashCode();
            compareTo = ObjectUtils.compare(hashCode1, hashCode2);

            String pattern = "propertyName:[{}],same propertyValue:[{}],hashCode1:[{}],hashCode2:[{}],result:[{}]";
            LOGGER.trace(pattern, propertyName, propertyValue1, hashCode1, hashCode2, compareTo);
            return compareTo;
        }

        String pattern = "propertyName:[{}],propertyValue1:[{}],propertyValue2:[{}],result:[{}]";
        LOGGER.trace(pattern, propertyName, propertyValue1, propertyValue2, compareTo);
        return compareTo;
    }
}