diff options
author | cbateman | 2007-05-16 22:30:39 +0000 |
---|---|---|
committer | cbateman | 2007-05-16 22:30:39 +0000 |
commit | 81457d55b860afb38403a45a7b153858ec3b6108 (patch) | |
tree | 0fc8a9da1f7d004c51a361b4326ff969292b99a6 | |
parent | 752b7467e02f22e72e4b75a59d143d5e43c4b9ec (diff) | |
download | webtools.jsf-81457d55b860afb38403a45a7b153858ec3b6108.tar.gz webtools.jsf-81457d55b860afb38403a45a7b153858ec3b6108.tar.xz webtools.jsf-81457d55b860afb38403a45a7b153858ec3b6108.zip |
Patch https://bugs.eclipse.org/bugs/attachment.cgi?id=64528 from https://bugs.eclipse.org/bugs/show_bug.cgi?id=163890.
Major performance improvement on EL bean resolution (Matthias Fuessel) plus regression JUnits (Cameron Bateman/Oracle).
4 files changed, 703 insertions, 36 deletions
diff --git a/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/internal/types/TypeInfo.java b/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/internal/types/TypeInfo.java new file mode 100644 index 000000000..0015b6f49 --- /dev/null +++ b/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/internal/types/TypeInfo.java @@ -0,0 +1,100 @@ +package org.eclipse.jst.jsf.common.internal.types; + +import org.eclipse.jdt.core.IType; +import org.eclipse.jst.jsf.context.symbol.IBeanMethodSymbol; +import org.eclipse.jst.jsf.context.symbol.IBeanPropertySymbol; + +/**This class contains all info that is cached for a given IType. + * @see org.eclipse.jst.jsf.common.internal.types.TypeInfoCache + * + * @author Matthias + */ +class TypeInfo { + + /**Empty String array. Used for the (usual) case when a type has no missing supertypes. + */ + public static String[] NO_NAMES = new String[0]; + + private IBeanMethodSymbol[] methods = null; + private IBeanPropertySymbol[] properties = null; + private IType[] supertypes = null; + private IType[] interfaceTypes = null; + private String[] missingSupertypeNames = null; + + /**Creates an empty TypeInfo object + */ + public TypeInfo() { + super(); + } + + /**Returns the method symbols. Returns <code>null</code> if none have been cached. + * @return the method symbols. May be null. + */ + public IBeanMethodSymbol[] getMethodSymbols() { + return methods; + } + + /**Returns the property symbols. Returns <code>null</code> if none have been cached. + * @return the property symbols. May be null. + */ + public IBeanPropertySymbol[] getPropertySymbols() { + return properties; + } + + /**Sets the methods symbols to be cached. + * @param methods - the method symbols + */ + public void setMethodSymbols(IBeanMethodSymbol[] methods) { + this.methods = methods; + } + + /**Sets the property symbols to be cached. + * @param properties - the property symbols + */ + public void setPropertySymbols(IBeanPropertySymbol[] properties) { + this.properties = properties; + } + + /**Returns the supertypes. Returns <code>null</code> if none have been cached. + * @return the supertypes. May be null. + */ + public IType[] getSupertypes() { + return supertypes; + } + + /**Sets the supertypes to be cached. + * @param superTypes - the property symbols + */ + public void setSupertypes(IType[] superTypes) { + this.supertypes = superTypes; + } + + /**Returns the interface types. Returns <code>null</code> if none have been cached. + * @return the interface types. May be null. + */ + public IType[] getInterfaceTypes() { + return interfaceTypes; + } + + /**Sets the interface types to be cached. + * @param interfaceTypes - the property symbols + */ + public void setInterfaceTypes(IType[] interfaceTypes) { + this.interfaceTypes = interfaceTypes; + } + + /**Returns the names of the missing supertypes. Returns <code>null</code> if none have been cached. + * @return the names of the missing supertypes. May be null. + */ + public String[] getMissingSupertypeNames() { + return missingSupertypeNames; + } + + /**Sets the supertypes to be cached. + * @param missingSupertypeNames - the names of the missing supertypes + */ + public void setMissingSupertypeNames(String[] missingSupertypeNames) { + this.missingSupertypeNames = missingSupertypeNames; + } + +} diff --git a/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/internal/types/TypeInfoCache.java b/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/internal/types/TypeInfoCache.java new file mode 100644 index 000000000..dcd0c29eb --- /dev/null +++ b/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/internal/types/TypeInfoCache.java @@ -0,0 +1,543 @@ +package org.eclipse.jst.jsf.common.internal.types; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.ElementChangedEvent; +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IElementChangedListener; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaElementDelta; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.ITypeHierarchy; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.internal.core.PackageFragment; +import org.eclipse.jst.jsf.common.JSFCommonPlugin; +import org.eclipse.jst.jsf.context.symbol.IBeanMethodSymbol; +import org.eclipse.jst.jsf.context.symbol.IBeanPropertySymbol; + +/**Provides a cache for java IType properties. It can cache bean property symbols, method symbols, + * supertypes and implemented interfaces per IType. The cache listens to changes in the java model + * and invalidates affected properties, but does not update them. + * + * @author Matthias + */ +public class TypeInfoCache implements IElementChangedListener { + + private static TypeInfoCache instance = null; + + /**Returns the TypeInfoCache instance. + * + * @return the TypeInfoCache instance + */ + public static synchronized TypeInfoCache getInstance() { + if (instance == null) { + instance = new TypeInfoCache(); + JavaCore.addElementChangedListener(instance, ElementChangedEvent.POST_CHANGE); + } + return instance; + } + + private final Map /*<IType, TypeInfo>*/ cachedInfo; + private final Map /*<ITypeRoot, Set<IType>>*/ cachedTypesByAffectingTypeRoot; + private final Map /*<String, Set<IType>>*/ cachedTypesByMissingSupertypename; + + private TypeInfoCache() { + cachedInfo = new HashMap(); + cachedTypesByAffectingTypeRoot = new HashMap(); + cachedTypesByMissingSupertypename = new HashMap(10); + } + + public void elementChanged(ElementChangedEvent event) { + updateChangedJavaElement(event.getDelta()); + } + + /**Returns the cached info({@link TypeInfo}) for a given type. Will + * return <code>null</code> if no info has been cached or the the type/something it depends on + * has changed since then. + * + * @param type - the type in question + * @return a TypeInfo instance that contains all cached info for the given type. May be null. + */ + protected TypeInfo getTypeInfo(IType type) { + TypeInfo info = null; + if (type != null) + { + info = (TypeInfo) cachedInfo.get(type); + } + return info; + } + + /**Returns the cached bean property symbols for a given type. Will return null if no + * bean property symbols have been cached or the type/something it depends on has changed since + * then. + * @param beanType - the bean type in question + * @return the bean property symbols for the given type. May be null. + * @see TypeInfoCache#cachePropertySymbols(IType, IBeanPropertySymbol[]) + */ + public synchronized IBeanPropertySymbol[] getCachedPropertySymbols(IType beanType) { + IBeanPropertySymbol[] props = null; + + if (beanType != null) + { + TypeInfo typeInfo = getTypeInfo(beanType); + if (typeInfo != null) + { + props = typeInfo.getPropertySymbols(); + } + } + return props; + } + + /**Returns the cached method symbols for a given type. Will return null if no + * method symbols have been cached or the type/something it depends on has changed since + * then. + * @param beanType - the bean type in question + * @return the method symbols for the given type. May be null. + * @see TypeInfoCache#cacheMethodSymbols(IType, IBeanMethodSymbol[]) + */ + public synchronized IBeanMethodSymbol[] getCachedMethodSymbols(IType beanType) { + IBeanMethodSymbol[] methods = null; + + if (beanType != null) + { + TypeInfo typeInfo = getTypeInfo(beanType); + if (typeInfo != null) + { + methods = typeInfo.getMethodSymbols(); + } + } + + return methods; + } + + /**Returns the cached supertypes for a given type. Will return null if no supertypes + * have been cached for this type or if the type/something it depends on has changed since + * then. + * @param type - the bean type in question + * @return the supertypes for the given type. May be null. + * @see TypeInfoCache#cacheSupertypesFor(IType) + */ + public synchronized IType[] getCachedSupertypes(IType type) { + IType[] types = null; + + if (type != null) + { + TypeInfo typeInfo = getTypeInfo(type); + if (typeInfo != null) + { + types = typeInfo.getSupertypes(); + } + } + + return types; + } + + /**Returns the cached implemented interfaces for a given type. Will return null if no interfaces + * have been cached for this type or if the type/something it depends on has changed since + * then. + * @param type - the bean type in question + * @return the interface types implemented by the given type. May be null. + * @see TypeInfoCache#cacheInterfaceTypesFor(IType) + */ + public synchronized IType[] getCachedInterfaceTypes(IType type) + { + IType[] types = null; + + if (type != null) + { + TypeInfo typeInfo = getTypeInfo(type); + if (typeInfo != null) + { + types = typeInfo.getInterfaceTypes(); + } + } + + return types; + } + + /**Caches the given method symbols for the given type. + * @param beanType - the type + * @param methods - the method symbols to cache + */ + public synchronized void cacheMethodSymbols(IType beanType, IBeanMethodSymbol[] methods) { + if (beanType != null) + { + TypeInfo typeInfo = getOrCreateTypeInfo(beanType); + if (typeInfo != null) { + typeInfo.setMethodSymbols(methods); + } + } + } + + /**Caches the given property symbols for the given type. + * @param beanType - the type + * @param properties - the property symbols to cache + */ + public synchronized void cachePropertySymbols(IType beanType, IBeanPropertySymbol[] properties) { + if (beanType != null) + { + TypeInfo typeInfo = getOrCreateTypeInfo(beanType); + if (typeInfo != null) { + typeInfo.setPropertySymbols(properties); + } + } + } + + /**Caches the supertypes for the given type. The supertypes will be calculated (and also returned) + * by this method. + * @param type - the type to cache supertypes for + * @return the supertypes of the given type. + */ + public synchronized IType[] cacheSupertypesFor(IType type) + { + IType[] types = null; + + if (type != null) + { + TypeInfo typeInfo = getOrCreateTypeInfo(type); + + if (typeInfo != null) + { + types = typeInfo.getSupertypes(); + } + } + return types; + } + + /**Caches the interface types for the given type. The interface types will be calculated (and also + * returned) by this method. + * @param type - the type to cache interface types for + * @return the interface types implemented by the given type. + */ + public synchronized IType[] cacheInterfaceTypesFor(IType type) + { + IType[] types = null; + + if (type != null) + { + TypeInfo typeInfo = getOrCreateTypeInfo(type); + if (typeInfo != null) + { + types = typeInfo.getInterfaceTypes(); + } + } + return types; + } + + /**Returns the TypeInfo for the given type. If no TypeInfo exists for this type, an empty TypeInfo + * will be created and cached. + * @param type - the type in question + * @return the (modifyable) TypeInfo for the given type + */ + protected TypeInfo getOrCreateTypeInfo(IType type) { + TypeInfo typeInfo = getTypeInfo(type); + if (typeInfo == null) { + try { + final ITypeHierarchy hierarchy = + type.newSupertypeHierarchy(new NullProgressMonitor()); + final IType[] supertypes = hierarchy.getAllSuperclasses(type); + final IType[] interfaceTypes = hierarchy.getAllInterfaces(); + final IType[] rootClasses = hierarchy.getRootClasses(); + List missingSupertypesList = null; + for (int i = 0; i < rootClasses.length; i++) { + String superclassName = rootClasses[i].getSuperclassName(); + if (superclassName != null) { + if (missingSupertypesList == null) { + missingSupertypesList = new ArrayList(1); + } + superclassName = shortTypename(superclassName); + missingSupertypesList.add(superclassName); + } + } + String[] missingSupertypes = null; + if (missingSupertypesList != null) { + missingSupertypes = (String[]) missingSupertypesList.toArray(new String[missingSupertypesList.size()]); + } else { + missingSupertypes = TypeInfo.NO_NAMES; + } + typeInfo = new TypeInfo(); + typeInfo.setSupertypes(supertypes); + typeInfo.setInterfaceTypes(interfaceTypes); + typeInfo.setMissingSupertypeNames(missingSupertypes); + cachedInfo.put(type, typeInfo); + registerCachedType(type, typeInfo); + } catch (JavaModelException e) { + JSFCommonPlugin.log(e); + } + } + return typeInfo; + } + + /**Returns the typename fragment after the last "." (which in most cases is identical to the + * unqualified typename). + * Used only to make sure that if n1 and n2 are names of the same type + * shortname(n1) equals shortname(2) even if one name is qualified and one not. + * @param typename + * @return the typename fragment after the last "." + */ + private String shortTypename(String typename) { + int pos = typename.lastIndexOf('.'); + if (pos >= 0) { + typename = typename.substring(pos + 1); + } + return typename; + } + + /** + * Registers the given type for all ITypeRoot's it depends on, so that it can be uncached if + * one of this ITypeRoot's has changed. The type must be unregistered when it should not be watched + * anymore. + * @param type - the type + * @param typeInfo - TypeInfo of the given type + * @see TypeInfoCache#unregisterCachedType(IType, TypeInfo) + */ + protected void registerCachedType(IType type, TypeInfo typeInfo) { + registerTypeForTypeRoot(type, type.getTypeRoot()); + IType[] supertypes = typeInfo.getSupertypes(); + for (int i = 0; i < supertypes.length; i++) { + registerTypeForTypeRoot(type, supertypes[i].getTypeRoot()); + } + String[] missingSupertypeNames = typeInfo.getMissingSupertypeNames(); + if (missingSupertypeNames != null) { + for (int i = 0; i < missingSupertypeNames.length; i++) { + registerTypeForMissingSupertype(type, missingSupertypeNames[i]); + } + } + } + + private void registerTypeForTypeRoot(IType type, ITypeRoot typeRoot) { + Set dependentTypes = (Set) cachedTypesByAffectingTypeRoot.get(typeRoot); + if (dependentTypes == null) { + dependentTypes = new HashSet(5); + cachedTypesByAffectingTypeRoot.put(typeRoot, dependentTypes); + } + dependentTypes.add(type); + } + + private void registerTypeForMissingSupertype(IType type, String supertype) { + Set dependentTypes = (Set) cachedTypesByMissingSupertypename.get(supertype); + if (dependentTypes == null) { + dependentTypes = new HashSet(5); + cachedTypesByMissingSupertypename.put(supertype, dependentTypes); + } + dependentTypes.add(type); + } + + /**Unregisters the given type for all ITypeRoot's it depended on. + * @param type - the type + * @param typeInfo - TypeInfo of the given type + */ + protected void unregisterCachedType(IType type, TypeInfo typeInfo) { + unregisterTypeForTypeRoot(type, type.getTypeRoot()); + IType[] supertypes = typeInfo.getSupertypes(); + for (int i = 0; i < supertypes.length; i++) { + unregisterTypeForTypeRoot(type, supertypes[i].getTypeRoot()); + } + String[] missingSupertypeNames = typeInfo.getMissingSupertypeNames(); + if (missingSupertypeNames != null) { + for (int i = 0; i < missingSupertypeNames.length; i++) { + unregisterTypeForMissingSupertype(type, missingSupertypeNames[i]); + } + } + } + + private void unregisterTypeForTypeRoot(IType type, ITypeRoot typeRoot) { + Set dependentTypes = (Set) cachedTypesByAffectingTypeRoot.get(typeRoot); + if (dependentTypes != null) { + dependentTypes.remove(type); + if (dependentTypes.isEmpty()) { + cachedTypesByAffectingTypeRoot.remove(typeRoot); + } + } + } + + private void unregisterTypeForMissingSupertype(IType type, String supertype) { + Set dependentTypes = (Set) cachedTypesByMissingSupertypename.get(supertype); + if (dependentTypes != null) { + dependentTypes.remove(type); + if (dependentTypes.isEmpty()) { + cachedTypesByMissingSupertypename.remove(supertype); + } + } + } + + /**This will remove all cached info for all types. + */ + protected synchronized void uncacheAllTypes() { + cachedInfo.clear(); + cachedTypesByAffectingTypeRoot.clear(); + cachedTypesByMissingSupertypename.clear(); + } + + /**Removes all cached info for all types that are subtypes of a type of the given ITypeRoot. + * @param typeRoot + */ + protected synchronized void uncacheAffectedTypes(ITypeRoot typeRoot) { + Collection affectedTypes = (Collection) cachedTypesByAffectingTypeRoot.get(typeRoot); + if (affectedTypes != null && !affectedTypes.isEmpty()) { + List affectedTypesCopy = new ArrayList(affectedTypes); + for (Iterator it = affectedTypesCopy.iterator(); it.hasNext(); ) { + IType cachedType = (IType) it.next(); + TypeInfo typeInfo = (TypeInfo) cachedInfo.remove(cachedType); + unregisterCachedType(cachedType, typeInfo); + } + } + } + + /**Removes all cached info for all types (or subtypes of types) that specify a supertype + * that has a name similar to the given name. + * @param supertypename - the missing supertype name. May be qualified or not + */ + protected synchronized void uncacheTypesWithMissingSupertype(String supertypename) { + Collection affectedTypes = (Collection) cachedTypesByMissingSupertypename.get(shortTypename(supertypename)); + if (affectedTypes != null && !affectedTypes.isEmpty()) { + List affectedTypesCopy = new ArrayList(affectedTypes); + for (Iterator it = affectedTypesCopy.iterator(); it.hasNext(); ) { + IType cachedType = (IType) it.next(); + TypeInfo typeInfo = (TypeInfo) cachedInfo.remove(cachedType); + unregisterCachedType(cachedType, typeInfo); + } + } + } + + /**Removes all cached info that may be affected by the given change. + * @param delta - the change in the java model + */ + protected void updateChangedJavaElement(IJavaElementDelta delta) { + IJavaElement element= delta.getElement(); + switch (element.getElementType()) { + case IJavaElement.JAVA_MODEL: + updateChangedJavaModel(delta, element); + break; + case IJavaElement.JAVA_PROJECT: + updateChangedJavaProject(delta, element); + break; + case IJavaElement.PACKAGE_FRAGMENT_ROOT: + updateChangedPackageFragmentRoot(delta, element); + break; + case IJavaElement.PACKAGE_FRAGMENT: + updateChangedPackageFragment(delta, (PackageFragment) element); + break; + case IJavaElement.CLASS_FILE: + case IJavaElement.COMPILATION_UNIT: + updateChangedOpenable(delta, element); + break; + } + } + + private void updateChangedChildren(IJavaElementDelta delta) { + if ((delta.getFlags() & IJavaElementDelta.F_CHILDREN) > 0) { + IJavaElementDelta[] children= delta.getAffectedChildren(); + for (int i= 0; i < children.length; i++) { + updateChangedJavaElement(children[i]); + } + } + } + + private void updateChangedJavaModel(IJavaElementDelta delta, IJavaElement element) { + switch (delta.getKind()) { + case IJavaElementDelta.ADDED : + case IJavaElementDelta.REMOVED : + uncacheAllTypes(); + break; + case IJavaElementDelta.CHANGED : + updateChangedChildren(delta); + break; + } + } + + private void updateChangedJavaProject(IJavaElementDelta delta, IJavaElement element) { + int kind = delta.getKind(); + int flags = delta.getFlags(); + if ((flags & IJavaElementDelta.F_OPENED) != 0) { + kind = IJavaElementDelta.ADDED; // affected in the same way + } + if ((flags & IJavaElementDelta.F_CLOSED) != 0) { + kind = IJavaElementDelta.REMOVED; // affected in the same way + } + switch (kind) { + case IJavaElementDelta.ADDED : + case IJavaElementDelta.REMOVED : + uncacheAllTypes(); + break; + case IJavaElementDelta.CHANGED : + updateChangedChildren(delta); + break; + } + } + + private void updateChangedPackageFragment(IJavaElementDelta delta, PackageFragment element) { + switch (delta.getKind()) { + case IJavaElementDelta.ADDED : + // if the package fragment is in the projects being considered, this could + // introduce new types, changing the hierarchy + case IJavaElementDelta.REMOVED : + // is a change if the package fragment contains supertypes? + uncacheAllTypes(); + break; + case IJavaElementDelta.CHANGED : + // look at the files in the package fragment + updateChangedChildren(delta); + } + } + + private void updateChangedPackageFragmentRoot(IJavaElementDelta delta, IJavaElement element) { + switch (delta.getKind()) { + case IJavaElementDelta.ADDED : + case IJavaElementDelta.REMOVED : + uncacheAllTypes(); + break; + case IJavaElementDelta.CHANGED : + int flags = delta.getFlags(); + if (((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) > 0)||(flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) > 0) { + uncacheAllTypes(); + } else { + updateChangedChildren(delta); + } + break; + } + } + + /**Removes all cached info that may be affected by the change in this IOpenable + * @param delta - the change in the java model + * @param element - the (changed) IOpenable considered + */ + protected void updateChangedOpenable(IJavaElementDelta delta, IJavaElement element) { + if (element instanceof ITypeRoot) { + ITypeRoot typeRoot = (ITypeRoot) element; + uncacheAffectedTypes(typeRoot); + // Creates missing superclass for any cached type? + if (delta.getKind() == IJavaElementDelta.ADDED) { + if (typeRoot instanceof ICompilationUnit) { + ICompilationUnit cu = (ICompilationUnit) typeRoot; + try { + IType[] types = cu.getAllTypes(); + for (int i = 0; i < types.length; i++) { + uncacheTypesWithMissingSupertype(types[i].getElementName()); + } + } catch (JavaModelException e) { + JSFCommonPlugin.log(IStatus.INFO, "Unable to get types for compilation unit " + cu, e); //$NON-NLS-1$ + uncacheAllTypes(); + } + } else if (typeRoot instanceof IClassFile) { + IClassFile cf = (IClassFile) typeRoot; + IType type = cf.getType(); + uncacheTypesWithMissingSupertype(type.getElementName()); + } + } + } + } + +} diff --git a/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/util/TypeUtil.java b/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/util/TypeUtil.java index 0389b4cfb..d26fac48b 100644 --- a/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/util/TypeUtil.java +++ b/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/common/util/TypeUtil.java @@ -80,7 +80,7 @@ public final class TypeUtil /** * Resolve typeSignature in the context of owningType. This method will return * a type erased signture if eraseTypeParameters == true and will attempt to - * resolve and include parameters if eraseTypeParamters + * resolve and include parameters if eraseTypeParamters == false * * NOTE: special rules apply to the way unresolved type parameters and wildcards * are resolved: @@ -102,7 +102,7 @@ public final class TypeUtil * i.e. List<?> -> Ljava.util.List<Ljava.lang.Object;>; * * - * The reason for this substitions is to return the most accurate reasonable approximation + * The reason for this substition is to return the most accurate reasonable approximation * of the type within what is known by owningType * * @param owningType @@ -413,12 +413,12 @@ public final class TypeUtil { if (type == null || !isEnumType(type)) { - throw new IllegalArgumentException("type must be non-null and isEnum()==true"); + throw new IllegalArgumentException("type must be non-null and isEnum()==true"); //$NON-NLS-1$ } if (fieldName == null) { - throw new IllegalArgumentException("fieldName must be non-null"); + throw new IllegalArgumentException("fieldName must be non-null"); //$NON-NLS-1$ } // if type is the java.lang.Enum, always true @@ -452,13 +452,13 @@ public final class TypeUtil { if (typeSig1 == null || typeSig2 == null) { - throw new IllegalArgumentException("args must not be null"); + throw new IllegalArgumentException("args must not be null"); //$NON-NLS-1$ } if (Signature.getTypeSignatureKind(typeSig1) != Signature.CLASS_TYPE_SIGNATURE || Signature.getTypeSignatureKind(typeSig2) != Signature.CLASS_TYPE_SIGNATURE) { - throw new IllegalArgumentException("args must be resolved class types"); + throw new IllegalArgumentException("args must be resolved class types"); //$NON-NLS-1$ } // if one or the other is the raw enum type, then they *may* be comparable; we don't know @@ -484,13 +484,13 @@ public final class TypeUtil { if (typeSig1 == null || typeSig2 == null) { - throw new IllegalArgumentException("args must not be null"); + throw new IllegalArgumentException("args must not be null"); //$NON-NLS-1$ } if (Signature.getTypeSignatureKind(typeSig1) != Signature.CLASS_TYPE_SIGNATURE || Signature.getTypeSignatureKind(typeSig2) != Signature.CLASS_TYPE_SIGNATURE) { - throw new IllegalArgumentException("args must be resolved class types"); + throw new IllegalArgumentException("args must be resolved class types"); //$NON-NLS-1$ } // if either one is the base enum type, then we can't be sure @@ -533,7 +533,7 @@ public final class TypeUtil catch (JavaModelException jme) { // log and fallthrough to return false - JSFCommonPlugin.log(jme, "Problem resolving isEnum"); + JSFCommonPlugin.log(jme, "Problem resolving isEnum"); //$NON-NLS-1$ } // if unresolved assume false diff --git a/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/context/symbol/internal/impl/IJavaTypeDescriptor2Impl.java b/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/context/symbol/internal/impl/IJavaTypeDescriptor2Impl.java index a1b1626db..60fcf9d8c 100644 --- a/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/context/symbol/internal/impl/IJavaTypeDescriptor2Impl.java +++ b/jsf/plugins/org.eclipse.jst.jsf.common/src/org/eclipse/jst/jsf/context/symbol/internal/impl/IJavaTypeDescriptor2Impl.java @@ -18,7 +18,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; @@ -29,10 +28,10 @@ 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.ITypeHierarchy; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jst.jsf.common.JSFCommonPlugin; +import org.eclipse.jst.jsf.common.internal.types.TypeInfoCache; import org.eclipse.jst.jsf.common.util.JDTBeanIntrospector; import org.eclipse.jst.jsf.common.util.JDTBeanProperty; import org.eclipse.jst.jsf.common.util.TypeUtil; @@ -177,6 +176,10 @@ public class IJavaTypeDescriptor2Impl extends ITypeDescriptorImpl implements IJa eNotify(new ENotificationImpl(this, Notification.SET, SymbolPackage.IJAVA_TYPE_DESCRIPTOR2__TYPE, oldType, type)); } + /** + * @see org.eclipse.jst.jsf.context.symbol.internal.impl.ITypeDescriptorImpl#getInterfaceTypeSignatures() + * @generated NOT + */ public EList getInterfaceTypeSignatures() { EList interfaces = new BasicEList(); @@ -185,22 +188,21 @@ public class IJavaTypeDescriptor2Impl extends ITypeDescriptorImpl implements IJa if (type_ != null) { - // TODO: type hierarchy is potentially expensive, should - // cache once and listen for changes - try { - final ITypeHierarchy hierarchy = - type_.newSupertypeHierarchy(new NullProgressMonitor()); - final IType[] interfaceTypes = hierarchy.getAllInterfaces(); - copySignatures(interfaces, interfaceTypes); - } catch (JavaModelException e) { - JSFCommonPlugin.log(e); + final TypeInfoCache typeInfoCache = TypeInfoCache.getInstance(); + IType[] interfaceTypes = typeInfoCache.getCachedInterfaceTypes(type_); + if (interfaceTypes == null) { + interfaceTypes = typeInfoCache.cacheInterfaceTypesFor(type_); } - + copySignatures(interfaces, interfaceTypes); } return interfaces; } + /** + * @see org.eclipse.jst.jsf.context.symbol.internal.impl.ITypeDescriptorImpl#getSuperTypeSignatures() + * @generated NOT + */ public EList getSuperTypeSignatures() { EList interfaces = new BasicEList(); @@ -209,16 +211,14 @@ public class IJavaTypeDescriptor2Impl extends ITypeDescriptorImpl implements IJa if (type_ != null) { - // TODO: type hierarchy is potentially expensive, should - // cache once and listen for changes - try { - final ITypeHierarchy hierarchy = - type_.newSupertypeHierarchy(new NullProgressMonitor()); - final IType[] interfaceTypes = hierarchy.getAllSuperclasses(type_); - copySignatures(interfaces, interfaceTypes); - } catch (JavaModelException e) { - JSFCommonPlugin.log(e); + final TypeInfoCache typeInfoCache = TypeInfoCache.getInstance(); + IType[] interfaceTypes = typeInfoCache.getCachedSupertypes(type_); + + if (interfaceTypes == null) + { + interfaceTypes = typeInfoCache.cacheSupertypesFor(type_); } + copySignatures(interfaces, interfaceTypes); } return interfaces; @@ -256,10 +256,23 @@ public class IJavaTypeDescriptor2Impl extends ITypeDescriptorImpl implements IJa * <!-- end-user-doc --> * @generated NOT */ - public EList getBeanProperties() { - BasicEList list = new BasicEList(); - list.addAll(getPropertiesInternal()); - return list; + public EList getBeanProperties() + { + TypeInfoCache typeInfoCache = TypeInfoCache.getInstance(); + IBeanPropertySymbol[] properties = typeInfoCache.getCachedPropertySymbols(type); + Collection propertyColl; + if (properties == null) { + propertyColl = getPropertiesInternal(); + properties = (IBeanPropertySymbol[]) propertyColl.toArray(new IBeanPropertySymbol[propertyColl.size()]); + typeInfoCache.cachePropertySymbols(type, properties); + } + else + { + propertyColl = new ArrayList(properties.length); + Collections.addAll(propertyColl, properties); + } + BasicEList list = new BasicEList(propertyColl); + return list; } /** @@ -269,8 +282,19 @@ public class IJavaTypeDescriptor2Impl extends ITypeDescriptorImpl implements IJa * @generated NOT */ public EList getBeanMethods() { - BasicEList list = new BasicEList(); - list.addAll(getMethodsInternal()); + TypeInfoCache typeInfoCache = TypeInfoCache.getInstance(); + IBeanMethodSymbol[] methods = typeInfoCache.getCachedMethodSymbols(type); + Collection methodColl; + if (methods == null) + { + methodColl = getMethodsInternal(); + methods = (IBeanMethodSymbol[]) methodColl.toArray(new IBeanMethodSymbol[methodColl.size()]); + typeInfoCache.cacheMethodSymbols(type, methods); + } else { + methodColl = new ArrayList(methods.length); + Collections.addAll(methodColl, methods); + } + BasicEList list = new BasicEList(methodColl); return list; } |