package org.springframework.ide.eclipse.data.jdt.core; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.CompletionContext; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposalComputer; import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext; import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.source.ISourceViewer; import org.springframework.ide.eclipse.data.internal.DataCorePlugin; import org.springframework.ide.eclipse.data.jdt.core.RepositoryInformation; import org.springsource.ide.eclipse.commons.core.SpringCoreUtils; import org.springsource.ide.eclipse.commons.core.StatusHandler; /** * @author Terry Denney * * Completion proposal computer for adding template methods for findBy... * methods. * * @since 3.2 * */ @SuppressWarnings("restriction") public class FindByMethodCompletionProposalComputer extends JavaCompletionProposalComputer { @Override public List<ICompletionProposal> computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) { if (!(context instanceof JavaContentAssistInvocationContext)) { return Collections.emptyList(); } JavaContentAssistInvocationContext javaContext = (JavaContentAssistInvocationContext) context; CompletionContext coreContext = javaContext.getCoreContext(); if (coreContext != null) { int tokenLocation = coreContext.getTokenLocation(); if ((tokenLocation & CompletionContext.TL_MEMBER_START) == 0) { return Collections.emptyList(); } } if (!SpringCoreUtils.isSpringProject(javaContext.getProject().getProject())) { return Collections.emptyList(); } ITextViewer viewer = context.getViewer(); IDocument document = viewer.getDocument(); try { int invocationOffset = context.getInvocationOffset(); int start = invocationOffset; int end = invocationOffset; while (start != 0 && Character.isUnicodeIdentifierPart(document.getChar(start - 1))) { start--; } if (start < 0) { return Collections.emptyList(); } String prefix = document.get(start, end - start); if (prefix != null && prefix.length() > 0 && !"findby".startsWith(prefix.toLowerCase()) && !prefix.toLowerCase().startsWith("findby")) { return Collections.emptyList(); } if (!(viewer instanceof ISourceViewer)) { return Collections.emptyList(); } IType expectedType = javaContext.getExpectedType(); if (expectedType == null) { expectedType = javaContext.getCompilationUnit().findPrimaryType(); } if (expectedType == null) { return Collections.emptyList(); } if (!isSpringDataRepository(expectedType, javaContext.getProject())) { return Collections.emptyList(); } List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>(); RepositoryInformation repositoryInfo = new RepositoryInformation(expectedType); Class<?> domainClass = repositoryInfo.getManagedDomainClass(); if (domainClass != null) { Method[] methods = domainClass.getMethods(); for (Method method : methods) { Class<?> returnType = method.getReturnType(); if ("void".equals(returnType.getName())) { continue; } if (method.getParameterTypes().length > 0) { continue; } String methodName = method.getName(); if (methodName.startsWith("get")) { String propertyName = methodName.substring(3, methodName.length()); if ("Class".equals(propertyName)) { continue; } String proposalMethodName = FindByMethodCompletionProposal.getMethodName(propertyName); if (!containsMethodName(proposalMethodName, expectedType)) { if (prefix != null && prefix.length() > 0 && proposalMethodName.toLowerCase().startsWith(prefix.toLowerCase())) { proposals.add(new FindByMethodCompletionProposal(propertyName, returnType, domainClass, start, end, javaContext)); } } } } } return proposals; } catch (BadLocationException e) { StatusHandler.log(new Status(Status.ERROR, DataCorePlugin.PLUGIN_ID, e.getMessage(), e)); } catch (JavaModelException e) { StatusHandler.log(new Status(Status.ERROR, DataCorePlugin.PLUGIN_ID, e.getMessage(), e)); } return Collections.emptyList(); } private boolean containsMethodName(String methodName, IType expectedType) { try { IMethod[] methods = expectedType.getMethods(); for (IMethod method : methods) { if (method.getElementName().equals(methodName)) { return true; } } } catch (JavaModelException e) { StatusHandler.log(new Status(Status.ERROR, DataCorePlugin.PLUGIN_ID, e.getMessage(), e)); } return false; } private static boolean isSpringDataRepository(IType type, IJavaProject project) throws JavaModelException { if (type == null) { return false; } if (isSpringDataRepository(type)) { return true; } String[] interfaces = type.getSuperInterfaceNames(); for (String extendedInterface : interfaces) { if (extendedInterface.contains("Repository")) { String[][] resolvedInterfaceTypes = type.resolveType(extendedInterface); if (resolvedInterfaceTypes == null) { continue; } for (String[] match : resolvedInterfaceTypes) { if (match != null && match.length == 2) { if (isSpringDataRepository(project.findType(match[0] + "." + match[1]), project)) { return true; } } } } } return false; } private static boolean isSpringDataRepository(IType type) { if (RepositoryInformation.isSpringDataRepository(type)) { return true; } return "org.springframework.data.repository.Repository".equals(type.getFullyQualifiedName()); } }