All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.spring.java.JavaUtils Maven / Gradle / Ivy

There is a newer version: RELEASE240
Show newest version
/*
 * 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 org.netbeans.modules.spring.java;

import java.awt.Dialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleElementVisitor6;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.text.Document;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.java.source.CancellableTask;
import org.netbeans.api.java.source.ClasspathInfo;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.ElementHandle;
import org.netbeans.api.java.source.ElementUtilities;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.SourceUtils;
import org.netbeans.api.java.source.Task;
import org.netbeans.api.java.source.ui.ElementOpen;
import org.netbeans.api.java.source.ui.ScanDialog;
import org.netbeans.api.progress.ProgressUtils;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.modules.spring.beans.utils.ElementSeekerTask;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.awt.StatusDisplayer;
import org.openide.filesystems.FileObject;
import org.openide.util.Mutex;
import org.openide.util.NbBundle;

/**
 *
 * @author Rohan Ranade ([email protected])
 */
public final class JavaUtils {

    private JavaUtils() {
        
    }

    public static Collection getMethodsFromHandles(CompilationInfo ci, Collection> methodHandles) {
        List methods = new ArrayList(methodHandles.size());
        for(ElementHandle handle : methodHandles) {
            ExecutableElement ee = handle.resolve(ci);
            if(ee != null) {
                methods.add(ee);
            }
        }
        
        return methods;
    }
    
    private static final String GET_PREFIX = "get"; // NOI18N
    private static final String SET_PREFIX = "set"; // NOI18N
    private static final String IS_PREFIX = "is"; // NOI18N
    
    public static boolean isGetter(ExecutableElement ee) {
        String methodName = ee.getSimpleName().toString();
        TypeMirror retType = ee.getReturnType();

        // discard private and static methods
        if (ee.getModifiers().contains(Modifier.PRIVATE) || ee.getModifiers().contains(Modifier.STATIC)) {
            return false;
        }
        
        
        boolean retVal = methodName.startsWith(GET_PREFIX) && methodName.length() > GET_PREFIX.length() && retType.getKind() != TypeKind.VOID;
        retVal = retVal || methodName.startsWith(IS_PREFIX) && methodName.length() > IS_PREFIX.length() && retType.getKind() == TypeKind.BOOLEAN;
        
        return retVal;
    }
    
    public static boolean isSetter(ExecutableElement ee) {
        String methodName = ee.getSimpleName().toString();
        TypeMirror retType = ee.getReturnType();
        
        // discard private and static methods
        if (ee.getModifiers().contains(Modifier.PRIVATE) || ee.getModifiers().contains(Modifier.STATIC)) {
            return false;
        }
        
        return methodName.startsWith(SET_PREFIX) && methodName.length() > SET_PREFIX.length() 
                && retType.getKind() == TypeKind.VOID && ee.getParameters().size() == 1;
    }
    
    public static String getPropertyName(String methodName) {
        if(methodName == null) {
            return null;
        }
        
        if(methodName.startsWith(GET_PREFIX) || methodName.startsWith(SET_PREFIX)) {
            String substring = methodName.substring(3);
            if (!"".equals(substring)) {
                return convertToPropertyName(substring);
            }
        } else if(methodName.startsWith(IS_PREFIX)) {
            String substring = methodName.substring(2);
            if (!"".equals(substring)) {
                return convertToPropertyName(substring);
            }
        }
        
        return null;
    }
    
    private static String convertToPropertyName(String name) {
        char[] vals = name.toCharArray();
        vals[0] = Character.toLowerCase(vals[0]);
        return String.valueOf(vals);
    }
    
    public static Collection> getOverridenMethodsAsHandles(ExecutableElement e, CompilationInfo info) {
        Collection methods = getOverridenMethods(e, info);
        if(methods.isEmpty()) {
            return Collections.emptyList();
        }
        
        Collection> handles = new ArrayList>(methods.size());
        for(ExecutableElement ee : methods) {
            handles.add(ElementHandle.create(ee));
        }
        
        return handles;
    }
    
    public static Collection getOverridenMethods(ExecutableElement e, CompilationInfo info) {
        return getOverridenMethods(e, SourceUtils.getEnclosingTypeElement(e), info);
    }

    private static Collection getOverridenMethods(ExecutableElement e, TypeElement parent, CompilationInfo info) {
        ArrayList result = new ArrayList();
        
        TypeMirror sup = parent.getSuperclass();
        if (sup.getKind() == TypeKind.DECLARED) {
            TypeElement next = (TypeElement) ((DeclaredType)sup).asElement();
            ExecutableElement overriden = getMethod(e, next, info);
                result.addAll(getOverridenMethods(e,next, info));
            if (overriden!=null) {
                result.add(overriden);
            }
        }
        for (TypeMirror tm:parent.getInterfaces()) {
            TypeElement next = (TypeElement) ((DeclaredType)tm).asElement();
            ExecutableElement overriden2 = getMethod(e, next, info);
            result.addAll(getOverridenMethods(e,next, info));
            if (overriden2!=null) {
                result.add(overriden2);
            }
        }
        return result;
    }    
    
    private static ExecutableElement getMethod(ExecutableElement method, TypeElement type, CompilationInfo info) {
        for (ExecutableElement met: ElementFilter.methodsIn(type.getEnclosedElements())){
            if (info.getElements().overrides(method, met, type)) {
                return met;
            }
        }
        return null;
    }

    @NbBundle.Messages("JavaUtils.title.method.searching=Searching Method")
    public static ElementHandle findMethod(FileObject fileObject, final String classBinName,
            final String methodName, int argCount, Public publicFlag, Static staticFlag) {
        JavaSource js = JavaUtils.getJavaSource(fileObject);
        if (js != null) {
            MethodFinder methodFinder = new MethodFinder(js, classBinName, methodName, argCount, publicFlag, staticFlag);
            methodFinder.runAsUserTask();
            if (methodFinder.getMethodHandle() == null && SourceUtils.isScanInProgress()) {
                if (!ScanDialog.runWhenScanFinished(methodFinder, Bundle.JavaUtils_title_method_searching())) {
                    return methodFinder.getMethodHandle();
                } else {
                    return null;
                }
            } else {
                return methodFinder.getMethodHandle();
            }
        }

        return null;
    }
    
    public static JavaSource getJavaSource(FileObject fileObject) {
        if (fileObject == null) {
            return null;
        }
        Project project = FileOwnerQuery.getOwner(fileObject);
        if (project == null) {
            return null;
        }
        // XXX this only works correctly with projects with a single sourcepath,
        // but we don't plan to support another kind of projects anyway (what about Maven?).
        SourceGroup[] sourceGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
        for (SourceGroup sourceGroup : sourceGroups) {
            return JavaSource.create(ClasspathInfo.create(sourceGroup.getRootFolder()));
        }
        return null;
    }
    
    public static JavaSource getJavaSource(Document doc) {
        return getJavaSource(NbEditorUtilities.getFileObject(doc));
    }
    
    public static TypeElement findClassElementByBinaryName(final String binaryName, CompilationController cc) {
        if (!binaryName.contains("$")) { // NOI18N
            // fast search based on fqn
            return cc.getElements().getTypeElement(binaryName);
        } else {
            // get containing package
            String packageName = ""; // NOI18N
            int dotIndex = binaryName.lastIndexOf("."); // NOI18N
            if (dotIndex != -1) {
                packageName = binaryName.substring(0, dotIndex);
            }
            PackageElement packElem = cc.getElements().getPackageElement(packageName);
            if (packElem == null) {
                return null;
            }

            // scan for element matching the binaryName
            return new BinaryNameTypeScanner().visit(packElem, binaryName);
        }
    }
    
    /**
     * Open the specified method of the specified class in the editor
     * 
     * @param doc The document on from which the java model context is to be created
     * @param classBinName binary name of the class whose method is to be opened in the editor
     * @param methodName name of the method
     * @param argCount number of arguments that the method has (-1 if caller doesn't care)
     * @param publicFlag YES if the method is public, NO if not, DONT_CARE if caller doesn't care
     * @param staticFlag YES if the method is static, NO if not, DONT_CARE if caller doesn't care
     */
    public static void openMethodInEditor(FileObject fileObject, final String classBinName,
            final String methodName, int argCount, Public publicFlag, Static staticFlag) {
        if (classBinName == null || methodName == null || fileObject == null) {
            return;
        }

        final JavaSource js = JavaUtils.getJavaSource(fileObject);
        if (js == null) {
            return;
        }

        final ElementHandle eh = JavaUtils.findMethod(fileObject, classBinName, methodName, argCount, publicFlag, staticFlag);
        if (eh != null) {
            try {
                js.runUserActionTask(new Task() {
                    @Override
                    public void run(CompilationController cc) throws Exception {
                        ExecutableElement ee = eh.resolve(cc);
                        ElementOpen.open(js.getClasspathInfo(), ee);
                    }
                }, true);
            } catch (IOException ex) {
                Logger.getLogger("global").log(Level.SEVERE, ex.getMessage(), ex);
            }
        }
    }

    @NbBundle.Messages("JavaUtils.title.class.searching=Searching Class...")
    public static void findAndOpenJavaClass(final String classBinaryName, FileObject fileObject) {
        if (classBinaryName == null || fileObject == null) {
            return;
        }

        final JavaSource js = JavaUtils.getJavaSource(fileObject);
        if (js != null) {
            final AtomicBoolean cancel = new AtomicBoolean(false);
            final ClassFinder classFinder = new ClassFinder(js, classBinaryName, cancel);
            if (SourceUtils.isScanInProgress()) {
                ScanDialog.runWhenScanFinished(new Runnable() {
                    @Override
                    public void run() {
                        ProgressUtils.runOffEventDispatchThread(classFinder, Bundle.JavaUtils_title_class_searching(), cancel, false);
                    }
                }, Bundle.JavaUtils_title_class_searching());
            } else {
                ProgressUtils.runOffEventDispatchThread(classFinder, Bundle.JavaUtils_title_class_searching(), cancel, false);
            }
        }
    }

    private static final class ClassFinder extends ElementSeekerTask {

        private final String classBinaryName;
        private final AtomicBoolean cancel;

        public ClassFinder(JavaSource javaSource, String classBinaryName, AtomicBoolean cancel) {
            super(javaSource);
            this.classBinaryName = classBinaryName;
            this.cancel = cancel;
        }

        @Override
        public void run(CompilationController controller) throws Exception {
            if (cancel.get()) { return; }
            boolean opened = false;
            if (classBinaryName == null) {
                return;
            }
            TypeElement element = JavaUtils.findClassElementByBinaryName(classBinaryName, controller);
            if (element != null) {
                elementFound.set(true);
                if (cancel.get()) { return; }
                opened = ElementOpen.open(javaSource.getClasspathInfo(), element);
            }
            if (!opened) {
                String msg = NbBundle.getMessage(JavaUtils.class, "LBL_SourceNotFound", classBinaryName); //NOI18N
                StatusDisplayer.getDefault().setStatusText(msg);
            }
        }
    }
    
    private static final class MethodFinder extends ElementSeekerTask {

        private String classBinName;
        private String methodName;
        private int argCount;
        private Public publicFlag;
        private Static staticFlag;
        private ElementHandle methodHandle;

        public MethodFinder(JavaSource javaSource, String classBinName, String methodName, int argCount, Public publicFlag, Static staticFlag) {
            super(javaSource);
            this.classBinName = classBinName;
            this.methodName = methodName;
            this.argCount = argCount;
            this.publicFlag = publicFlag;
            this.staticFlag = staticFlag;
        }

        @Override
        public void run(CompilationController cc) throws Exception {
            cc.toPhase(Phase.ELEMENTS_RESOLVED);
            TypeElement element = findClassElementByBinaryName(classBinName, cc);
            while (element != null) {
                List methods = ElementFilter.methodsIn(element.getEnclosedElements());
                for (ExecutableElement method : methods) {
                    // name match
                    String mName = method.getSimpleName().toString();
                    if (!mName.equals(methodName)) {
                        continue;
                    }

                    // argument match
                    if (this.argCount != -1) {
                        int actualArgCount = method.getParameters().size();
                        if (actualArgCount != argCount) {
                            continue;
                        }
                    }

                    // static match
                    if (staticFlag != Static.DONT_CARE) {
                        boolean isStatic = method.getModifiers().contains(Modifier.STATIC);
                        if ((isStatic && staticFlag == Static.NO) || (!isStatic && staticFlag == Static.YES)) {
                            continue;
                        }
                    }

                    // public match
                    if (publicFlag != Public.DONT_CARE) {
                        boolean isPublic = method.getModifiers().contains(Modifier.PUBLIC);
                        if ((isPublic && publicFlag == Public.NO) || (!isPublic && publicFlag == Public.YES)) {
                            continue;
                        }
                    }

                    // found!
                    this.methodHandle = ElementHandle.create(method);
                    return;
                }

                TypeMirror superClassMirror = element.getSuperclass();
                if (superClassMirror instanceof DeclaredType) {
                    DeclaredType declaredType = (DeclaredType) superClassMirror;
                    Element elem = declaredType.asElement();
                    if (elem.getKind() == ElementKind.CLASS) {
                        element = (TypeElement) elem;
                    }
                } else {
                    element = null;
                }
            }
        }

        public ElementHandle getMethodHandle() {
            return this.methodHandle;
        }
    }
    
    private static class BinaryNameTypeScanner extends SimpleElementVisitor6 {

        @Override
        public TypeElement visitPackage(PackageElement packElem, String binaryName) {
            for(Element e : packElem.getEnclosedElements()) {
                if(e.getKind().isClass()) {
                    TypeElement ret = e.accept(this, binaryName);
                    if(ret != null) {
                        return ret;
                    }
                }
            }
            
            return null;
        }

        @Override
        public TypeElement visitType(TypeElement typeElement, String binaryName) {
            String bName = ElementUtilities.getBinaryName(typeElement);
            if(binaryName.equals(bName)) {
                return typeElement;
            } else if(binaryName.startsWith(bName)) {
                for(Element child : typeElement.getEnclosedElements()) {
                    if(!child.getKind().isClass()) {
                        continue;
                    }
                    
                    TypeElement retVal = child.accept(this, binaryName);
                    if(retVal != null) {
                        return retVal;
                    }
                }
            }
            
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy