net.sf.guavaeclipse.creator.CompareMethodCreator.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.guavaeclipse.creator.CompareMethodCreator.java

Source

/*
 * Copyright 2014
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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 net.sf.guavaeclipse.creator;

import static net.sf.guavaeclipse.preferences.UserPreferenceUtil.getCompareToCommentsType;

import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;

import net.sf.guavaeclipse.dto.MethodInsertionPoint;
import net.sf.guavaeclipse.preferences.CompareToCommentsType;
import net.sf.guavaeclipse.utils.Utils;

public class CompareMethodCreator extends AbstractMethodCreator {

    private final CompareToCommentsType compareToCommentsType;

    public CompareMethodCreator(MethodInsertionPoint insertionPoint, List<String> fields)
            throws JavaModelException {
        super(insertionPoint, fields);
        compareToCommentsType = getCompareToCommentsType();
    }

    @Override
    public void generate() throws JavaModelException {
        super.generate();

        addImplementsComparable();
    }

    @SuppressWarnings("rawtypes")
    @Override
    protected String getMethodContent() throws JavaModelException {
        StringBuilder content = new StringBuilder();
        content.append("@Override\n");
        content.append("public int compareTo(");

        String variableName = "that";
        final IType currentClass = insertionPoint.getInsertionType();
        IType parentCompareToClass = getParentCompareToClass(currentClass);
        if (parentCompareToClass != null) {
            content.append(parentCompareToClass.getElementName());
        } else {
            content.append(currentClass.getElementName());
        }
        content.append(" " + variableName + "){\n");

        if (parentCompareToClass != null) {
            content.append("  if ( !( that instanceof " + currentClass.getElementName() + ")) {\n");
            content.append("  // XXX check  \n");
            content.append("    throw new RuntimeException(\"that is not of type "
                    + currentClass.getFullyQualifiedName() + "\");\n");
            content.append("  } \n");
            content.append("\n");
            content.append(currentClass.getElementName() + " obj = (" + currentClass.getElementName() + ") "
                    + variableName + ";");
            variableName = "obj";
        }

        StringBuilder commentSection = null;
        StringBuilder comparisonChain = new StringBuilder();

        comparisonChain.append("    return ComparisonChain.start()\n");
        if (parentCompareToClass != null) {
            comparisonChain
                    .append("     // XXX implement parent compare by yourself. This code won't work   .compare((")
                    .append(parentCompareToClass.getElementName()).append(") this, (")
                    .append(parentCompareToClass.getElementName()).append(") ").append(variableName).append(")\n");
        }

        for (Iterator<String> iterator = fields.iterator(); iterator.hasNext();) {
            String field = iterator.next();
            String commentMsg = "";
            boolean appendField = false;
            List<IField> sample = Utils.getFields(currentClass);
            for (Iterator s = sample.iterator(); s.hasNext();) {
                IField iField = (IField) s.next();
                if (iField.getElementName().equals(field)) {
                    // System.out.println("ElementName="+iField.getElementName());
                    // handling arrays...
                    if (iField.getTypeSignature().startsWith("[")) {
                        commentMsg = "is an Array! and they are not comparable by default";
                        appendField = false;
                        break;
                    }
                    // handling primitives
                    if (iField.getTypeSignature().length() == 1) {
                        appendField = true;
                        break;
                    }
                    String[][] type = iField.getDeclaringType().resolveType(
                            iField.getTypeSignature().substring(1, iField.getTypeSignature().length() - 1));
                    if (type != null) {
                        String fullQualifiedClassName = type[0][0] + "." + type[0][1];
                        // System.out.println("Searching for Class = "+fullQualifiedClassName);
                        if ("java.lang.Object".equals(fullQualifiedClassName)) {
                            commentMsg = "java.lang.Object is not comparable";
                            appendField = false;
                            break;
                        }
                        IType findType = iField.getJavaProject().findType(fullQualifiedClassName);
                        if (findType != null) {
                            if (doesImplementsComparable(findType)) {
                                appendField = true;
                            } else {
                                commentMsg = " does not implements java.lang.Comparable";
                                appendField = false;
                            }
                        } else {
                            appendField = false;
                        }
                        break;
                    } else {
                        appendField = true;
                    }

                }
            }
            if (appendField) {
                // System.out.println(field +" isComparable");
                comparisonChain.append("    .compare(this.").append(field).append(", " + variableName + ".")
                        .append(field).append(")\n");
            } else {
                // System.out.println(field +" NOT Comparable");
                switch (compareToCommentsType) {
                case EVERY_FIELD_COMMENT:
                    if (commentMsg == null || commentMsg.trim().isEmpty()) {
                        commentMsg = "is not comparable";
                    }
                    comparisonChain.append("// XXX field '" + field + "' " + commentMsg + " \n");
                    break;
                case ONLY_ONE_COMMENT:
                    if (commentSection == null) {
                        commentSection = new StringBuilder();
                    }
                    if (commentSection.length() == 0) {
                        commentSection.append(
                                "// XXX check the comment lines, because variables do not implement java.lang.Comparable or they are not comparable at all like arrays \n");
                    }
                case NO_COMMENTS:
                    // do nothing because user wants no comment
                    break;
                }
                comparisonChain.append("//.compare(this.").append(field).append(", " + variableName + ".")
                        .append(field).append(")\n");
            }
            // System.out.println("***************************");
        }

        comparisonChain.append("    .result();\n");

        if (commentSection != null) {
            content.append(commentSection);
        }
        content.append(comparisonChain);
        content.append("}");
        return content.toString();
    }

    @Override
    protected String getPackageToImport() {
        return "com.google.common.collect.ComparisonChain";
    }

    @Override
    protected String getMethodToDelete() {
        return "compareTo";
    }

    private IType getParentCompareToClass(final IType currentClass) throws JavaModelException {
        ITypeHierarchy a = currentClass.newSupertypeHierarchy(new NullProgressMonitor());
        IType[] allSuperClasses = a.getAllSuperclasses(currentClass);
        for (int i = 0; i < allSuperClasses.length; i++) {
            IType superClass = allSuperClasses[i];
            if ("java.lang.Object".equals(superClass.getFullyQualifiedName())) {
                // reached end
                return null;
            }
            IMethod[] methods = superClass.getMethods();
            for (int j = 0; j < methods.length; j++) {
                IMethod method = methods[i];
                if ("compareTo".equals(method.getElementName())) {
                    return superClass;
                }
            }
        }
        return null;
    }

    private void addImplementsComparable() throws JavaModelException {
        ICompilationUnit compilationUnit = getCompilationUnit();
        if (compilationUnit != null)
            addImplementsComparable(compilationUnit.getTypes()[0]);

    }

    private boolean doesImplementsComparable(IType type) throws JavaModelException {

        // get hierarchy
        ITypeHierarchy hierarchy = type.newTypeHierarchy(null);
        // hierarchy.getRootInterfaces();
        // get interfaces starting from superclass
        IType[] interfaces = hierarchy.getAllInterfaces();

        // does superclass implements comparable?
        // System.out.println("interfaces for "+type.getElementName()+" = "+interfaces.length);
        for (int j = 0; j < interfaces.length; j++) {
            // System.out.println(" "+interfaces[j].getKey());
            if (interfaces[j].getFullyQualifiedName().equals("java.lang.Comparable")) //$NON-NLS-1$
            {
                return true;
            }
        }

        return false;
    }

    private void addImplementsComparable(IType type) throws JavaModelException {

        // does class already implements comparable?
        IType[] interfaces = type.newSupertypeHierarchy(null).getAllInterfaces();
        for (int j = 0, size = interfaces.length; j < size; j++) {
            if (interfaces[j].getFullyQualifiedName().equals("java.lang.Comparable")) //$NON-NLS-1$
            {
                return;
            }
        }

        // find class declaration
        ISourceRange nameRange = type.getNameRange();

        // no declaration??
        if (nameRange == null) {
            return;
        }

        // offset for END of class name
        int offset = nameRange.getOffset() + nameRange.getLength();

        IBuffer buffer = type.getCompilationUnit().getBuffer();
        String contents = buffer.getText(offset, buffer.getLength() - offset);

        // warning, this doesn't handle "implements" and "{" contained in
        // comments in the middle of the declaration!
        int indexOfPar = contents.indexOf("{"); //$NON-NLS-1$

        contents = contents.substring(0, indexOfPar);

        int indexOfImplements = contents.indexOf("implements"); //$NON-NLS-1$
        if (indexOfImplements > -1) {
            buffer.replace(offset + indexOfImplements + "implements".length()//$NON-NLS-1$
                    , 0, " Comparable<" + type.getElementName() + ">,"); //$NON-NLS-1$
        } else {
            buffer.replace(offset, 0, " implements Comparable<" + type.getElementName() + ">"); //$NON-NLS-1$
        }

        buffer.save(null, false);
        buffer.close();

    }
}