public int compareTo()

in core/src/main/java/com/alibaba/fastjson2/reader/FieldReader.java [193:368]


    public int compareTo(FieldReader o) {
        int nameCompare = this.fieldName.compareTo(o.fieldName);
        if (nameCompare != 0) {
            if (this.ordinal < o.ordinal) {
                return -1;
            }
            if (this.ordinal > o.ordinal) {
                return 1;
            }

            return nameCompare;
        }

        int cmp = (isReadOnly() == o.isReadOnly()) ? 0 : (isReadOnly() ? 1 : -1);
        if (cmp != 0) {
            return cmp;
        }

        Member thisMember = this.field != null ? this.field : this.method;
        Member otherMember = o.field != null ? o.field : o.method;
        if (thisMember != null && otherMember != null && thisMember.getClass() != otherMember.getClass()) {
            Class otherDeclaringClass = otherMember.getDeclaringClass();
            Class thisDeclaringClass = thisMember.getDeclaringClass();
            if (thisDeclaringClass != otherDeclaringClass
            ) {
                if (thisDeclaringClass.isAssignableFrom(otherDeclaringClass)) {
                    return 1;
                } else if (otherDeclaringClass.isAssignableFrom(thisDeclaringClass)) {
                    return -1;
                }
            }
        }

        if (this.field != null && o.field != null) {
            Class<?> thisDeclaringClass = this.field.getDeclaringClass();
            Class<?> otherDeclaringClass = o.field.getDeclaringClass();

            for (Class s = thisDeclaringClass.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {
                if (s == otherDeclaringClass) {
                    return 1;
                }
            }

            for (Class s = otherDeclaringClass.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {
                if (s == thisDeclaringClass) {
                    return -1;
                }
            }
        }

        if (this.method != null && o.method != null) {
            Class<?> thisDeclaringClass = this.method.getDeclaringClass();
            Class<?> otherDeclaringClass = o.method.getDeclaringClass();
            //declaring class compare
            if (thisDeclaringClass != otherDeclaringClass) {
                for (Class s = thisDeclaringClass.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {
                    if (s == otherDeclaringClass) {
                        return -1;
                    }
                }
                for (Class s = otherDeclaringClass.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {
                    if (s == thisDeclaringClass) {
                        return 1;
                    }
                }
            }

            if (this.method.getParameterCount() == 1 && o.method.getParameterCount() == 1) {
                Class<?> thisParamType = this.method.getParameterTypes()[0];
                Class<?> otherParamType = o.method.getParameterTypes()[0];

                if (thisParamType != otherParamType) {
                    if (thisParamType.isAssignableFrom(otherParamType)) {
                        return 1;
                    }

                    if (otherParamType.isAssignableFrom(thisParamType)) {
                        return -1;
                    }

                    // Collection first
                    if (Collection.class.isAssignableFrom(otherParamType) && !Collection.class.isAssignableFrom(thisParamType)) {
                        return 1;
                    }

                    if (Collection.class.isAssignableFrom(thisParamType) && !Collection.class.isAssignableFrom(otherParamType)) {
                        return -1;
                    }

                    // field class compare
                    if (needCompareToActualFieldClass(thisParamType) || needCompareToActualFieldClass(otherParamType)) {
                        Class actualFieldClass = null;
                        try {
                            actualFieldClass = thisDeclaringClass.getDeclaredField(this.fieldName).getType();
                            if (actualFieldClass == null) {
                                actualFieldClass = otherDeclaringClass.getDeclaredField(this.fieldName).getType();
                            }
                        } catch (NoSuchFieldException ignored) {
                            // ignored
                        }
                        if (actualFieldClass != null) {
                            for (Class s = thisParamType; s != null && s != Object.class; s = s.getSuperclass()) {
                                if (s == actualFieldClass) {
                                    return -1;
                                }
                            }
                            for (Class s = otherParamType; s != null && s != Object.class; s = s.getSuperclass()) {
                                if (s == actualFieldClass) {
                                    return 1;
                                }
                            }
                        }
                    }
                    //JSONField annotation priority over non JSONField annotation
                    JSONField thisAnnotation = BeanUtils.findAnnotation(this.method, JSONField.class);
                    JSONField otherAnnotation = BeanUtils.findAnnotation(o.method, JSONField.class);
                    boolean thisAnnotatedWithJsonFiled = thisAnnotation != null;
                    if (thisAnnotatedWithJsonFiled == (otherAnnotation == null)) {
                        return thisAnnotatedWithJsonFiled ? -1 : 1;
                    }
                }
            }

            String thisMethodName = this.method.getName();
            String otherMethodName = o.method.getName();
            if (!thisMethodName.equals(otherMethodName)) {
                //setter priority over non setter
                boolean thisMethodNameSetStart = thisMethodName.startsWith("set");
                if (thisMethodNameSetStart != otherMethodName.startsWith("set")) {
                    return thisMethodNameSetStart ? -1 : 1;
                }
                //different field name priority over same field name
                String thisName = BeanUtils.setterName(thisMethodName, null);
                String otherName = BeanUtils.setterName(otherMethodName, null);
                boolean thisFieldNameEquals = this.fieldName.equals(thisName);
                if (thisFieldNameEquals != o.fieldName.equals(otherName)) {
                    return thisFieldNameEquals ? 1 : -1;
                }
            }
        }

        ObjectReader thisInitReader = this.getInitReader();
        ObjectReader otherInitReader = o.getInitReader();
        if (thisInitReader != null && otherInitReader == null) {
            return -1;
        }

        if (thisInitReader == null && otherInitReader != null) {
            return 1;
        }

        Class thisFieldClass = this.fieldClass;
        Class otherClass = o.fieldClass;

        boolean thisClassPrimitive = thisFieldClass.isPrimitive();
        boolean otherClassPrimitive = otherClass.isPrimitive();
        if (thisClassPrimitive && !otherClassPrimitive) {
            return -1;
        }

        if (!thisClassPrimitive && otherClassPrimitive) {
            return 1;
        }

        boolean thisClassStartsWithJava = thisFieldClass.getName().startsWith("java.");
        boolean otherClassStartsWithJava = otherClass.getName().startsWith("java.");
        if (thisClassStartsWithJava && !otherClassStartsWithJava) {
            return -1;
        }

        if (!thisClassStartsWithJava && otherClassStartsWithJava) {
            return 1;
        }

        return cmp;
    }