Java tutorial
/*-****************************************************************************** * Copyright (c) 2014 Iwao AVE!. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Iwao AVE! - initial API and implementation and/or initial documentation *******************************************************************************/ package net.harawata.mybatipse.bean; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import net.harawata.mybatipse.Activator; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; 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.core.Signature; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jface.text.contentassist.ICompletionProposal; /** * @author Iwao AVE! */ public class BeanPropertyCache { private static final Map<IProject, Map<String, BeanPropertyInfo>> projectCache = new ConcurrentHashMap<IProject, Map<String, BeanPropertyInfo>>(); public static void clearBeanPropertyCache() { projectCache.clear(); } public static void clearBeanPropertyCache(IProject project) { projectCache.remove(project); } public static void clearBeanPropertyCache(IProject project, String qualifiedName) { Map<String, BeanPropertyInfo> beans = projectCache.get(project); if (beans != null) { beans.remove(removeExtension(qualifiedName)); } } public static BeanPropertyInfo getBeanPropertyInfo(IJavaProject project, String fqn) { if (fqn == null) { return null; } String qualifiedName = removeExtension(fqn); Map<String, BeanPropertyInfo> beans = projectCache.get(project.getProject()); if (beans == null) { beans = new ConcurrentHashMap<String, BeanPropertyInfo>(); projectCache.put(project.getProject(), beans); } BeanPropertyInfo beanProps = beans.get(qualifiedName); if (beanProps == null) { final Map<String, String> readableFields = new LinkedHashMap<String, String>(); final Map<String, String> writableFields = new LinkedHashMap<String, String>(); parseBean(project, qualifiedName, readableFields, writableFields); beanProps = new BeanPropertyInfo(readableFields, writableFields); } beans.put(qualifiedName, beanProps); return beanProps; } protected static void parseBean(IJavaProject project, String qualifiedName, final Map<String, String> readableFields, final Map<String, String> writableFields) { try { final IType type = project.findType(qualifiedName); if (type != null) { if (type.isBinary()) { parseBinary(project, type, readableFields, writableFields); } else { parseSource(project, type, readableFields, writableFields); } } } catch (JavaModelException e) { Activator.log(Status.ERROR, "Failed to find type " + qualifiedName, e); } } protected static void parseBinary(IJavaProject project, final IType type, final Map<String, String> readableFields, final Map<String, String> writableFields) throws JavaModelException { parseBinaryFields(type, readableFields, writableFields); parseBinaryMethods(type, readableFields, writableFields); String superclass = Signature.toString(type.getSuperclassTypeSignature()); if (!Object.class.getName().equals(superclass)) { parseBean(project, superclass, readableFields, writableFields); } } protected static void parseBinaryMethods(final IType type, final Map<String, String> readableFields, final Map<String, String> writableFields) throws JavaModelException { for (IMethod method : type.getMethods()) { int flags = method.getFlags(); if (Flags.isPublic(flags)) { final String methodName = method.getElementName(); final int parameterCount = method.getParameters().length; final String returnType = method.getReturnType(); if (Signature.C_VOID == returnType.charAt(0)) { if (BeanPropertyVisitor.isSetter(methodName, parameterCount)) { String fieldName = BeanPropertyVisitor.getFieldNameFromAccessor(methodName); String paramType = method.getParameterTypes()[0]; writableFields.put(fieldName, Signature.toString(paramType)); } } else { if (BeanPropertyVisitor.isGetter(methodName, parameterCount)) { String fieldName = BeanPropertyVisitor.getFieldNameFromAccessor(methodName); readableFields.put(fieldName, Signature.toString(returnType)); } } } } } protected static void parseBinaryFields(final IType type, final Map<String, String> readableFields, final Map<String, String> writableFields) throws JavaModelException { for (IField field : type.getFields()) { int flags = field.getFlags(); if (Flags.isPublic(flags)) { String fieldName = field.getElementName(); String qualifiedType = Signature.toString(field.getTypeSignature()); readableFields.put(fieldName, qualifiedType); if (!Flags.isFinal(flags)) { writableFields.put(fieldName, qualifiedType); } } } } protected static void parseSource(IJavaProject project, final IType type, final Map<String, String> readableFields, final Map<String, String> writableFields) throws JavaModelException { ICompilationUnit compilationUnit = (ICompilationUnit) type.getAncestor(IJavaElement.COMPILATION_UNIT); ASTParser parser = ASTParser.newParser(AST.JLS4); parser.setKind(ASTParser.K_COMPILATION_UNIT); parser.setSource(compilationUnit); parser.setResolveBindings(true); // parser.setIgnoreMethodBodies(true); CompilationUnit astUnit = (CompilationUnit) parser.createAST(null); astUnit.accept(new BeanPropertyVisitor(project, readableFields, writableFields)); } public static Map<String, String> searchFields(IJavaProject project, String qualifiedName, String matchStr, boolean includeReadOnly, int currentIdx, boolean isValidation) { final Map<String, String> results = new LinkedHashMap<String, String>(); String searchStr; final int startIdx = currentIdx + 1; final int dotIdx = getDotIndex(matchStr, startIdx); if (dotIdx == -1) searchStr = matchStr.substring(startIdx); else searchStr = matchStr.substring(startIdx, dotIdx); final int bracePos = searchStr.indexOf("["); searchStr = bracePos > -1 ? searchStr.substring(0, bracePos) : searchStr; final boolean isPrefixMatch = !isValidation && dotIdx == -1; final BeanPropertyInfo beanProperty = getBeanPropertyInfo(project, qualifiedName); if (beanProperty != null) { final Map<String, String> fields = includeReadOnly ? beanProperty.getReadableFields() : beanProperty.getWritableFields(); for (Entry<String, String> entry : fields.entrySet()) { final String fieldName = entry.getKey(); final String fieldQualifiedName = entry.getValue(); if (matched(fieldName, searchStr, isPrefixMatch)) { if (dotIdx > -1) { return searchFields(project, fieldQualifiedName, matchStr, includeReadOnly, dotIdx, isValidation); } else { results.put(fieldName, fieldQualifiedName); } } } } return results; } public static List<ICompletionProposal> buildFieldNameProposal(Map<String, String> fields, final String input, final int offset, final int replacementLength) { List<ICompletionProposal> proposalList = new ArrayList<ICompletionProposal>(); int lastDot = input.lastIndexOf("."); String prefix = lastDot > -1 ? input.substring(0, lastDot) : ""; int relevance = fields.size(); for (Entry<String, String> fieldEntry : fields.entrySet()) { String fieldName = fieldEntry.getKey(); String qualifiedName = fieldEntry.getValue(); StringBuilder replaceStr = new StringBuilder(); if (lastDot > -1) replaceStr.append(prefix).append('.'); replaceStr.append(fieldName); StringBuilder displayStr = new StringBuilder(); displayStr.append(fieldName).append(" - ").append(qualifiedName); ICompletionProposal proposal = new JavaCompletionProposal(replaceStr.toString(), offset, replacementLength, replaceStr.length(), Activator.getIcon(), displayStr.toString(), null, null, relevance--); proposalList.add(proposal); } return proposalList; } private static String removeExtension(String src) { if (src != null && src.endsWith(".java")) return src.substring(0, src.length() - 5); else return src; } private static int getDotIndex(String str, int startIdx) { boolean isIndexedProperty = false; for (int i = startIdx; i < str.length(); i++) { char c = str.charAt(i); if (!isIndexedProperty && c == '.') return i; else if (!isIndexedProperty && c == '[') isIndexedProperty = true; else if (c == ']') isIndexedProperty = false; } return -1; } private static boolean matched(String fieldName, String searchStr, boolean prefixMatch) { return (searchStr == null || searchStr.length() == 0) || (prefixMatch ? fieldName.toLowerCase().startsWith(searchStr.toLowerCase()) : fieldName.equals(searchStr)); } }