Make classloaders final in JTypeQName

This commit is contained in:
Clément Fournier
2018-06-27 17:52:30 +02:00
parent 0ae88f7cd0
commit 44e23e7d2e
3 changed files with 24 additions and 31 deletions

View File

@ -41,9 +41,9 @@ public final class JavaTypeQualifiedName extends JavaQualifiedName {
private Class<?> representedType;
private boolean typeLoaded;
private ClassLoader classLoader;
private final ClassLoader classLoader;
JavaTypeQualifiedName(ImmutableList<String> packages, ImmutableList<String> classes, ImmutableList<Integer> localIndices) {
JavaTypeQualifiedName(ImmutableList<String> packages, ImmutableList<String> classes, ImmutableList<Integer> localIndices, ClassLoader classLoader) {
Objects.requireNonNull(packages);
Objects.requireNonNull(classes);
Objects.requireNonNull(localIndices);
@ -55,16 +55,8 @@ public final class JavaTypeQualifiedName extends JavaQualifiedName {
this.packages = packages;
this.classes = classes;
this.localIndices = localIndices;
}
/**
* Sets the classloader to be used when resolving the actual type of this qualified name.
* @see #getType()
*/
JavaTypeQualifiedName withClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
return this;
this.classLoader = classLoader; // classLoader may be null
}
@ -177,17 +169,15 @@ public final class JavaTypeQualifiedName extends JavaQualifiedName {
*/
public Class<?> getType() {
synchronized (this) {
if (typeLoaded) {
return representedType;
} else {
if (!typeLoaded) {
typeLoaded = true;
try {
representedType = loadType();
} catch (ClassNotFoundException e) {
representedType = null;
}
return representedType;
}
return representedType;
}
}

View File

@ -15,6 +15,8 @@ import net.sourceforge.pmd.lang.java.qname.ImmutableList.ListFactory;
/**
* Static factory methods for JavaQualifiedName.
* These are intended only for tests, even though some deprecated
* APIs use it. May be moved to an internal package?
*
* @author Clément Fournier
* @since 6.1.0
@ -108,13 +110,10 @@ public final class QualifiedNameFactory {
name = '.' + name; // unnamed package, marked by a full stop. See ofString's format below
}
JavaTypeQualifiedName qualifiedName = (JavaTypeQualifiedName) ofString(name);
if (qualifiedName != null) {
// Note: this assumes, that clazz has been loaded through the correct classloader,
// specifically through the auxclasspath classloader.
qualifiedName.withClassLoader(clazz.getClassLoader());
}
return qualifiedName;
// Note: this assumes, that clazz has been loaded through the correct classloader,
// specifically through the auxclasspath classloader.
// But this method should only be used in tests anyway
return (JavaTypeQualifiedName) ofStringWithClassLoader(name, clazz.getClassLoader());
}
@ -146,6 +145,10 @@ public final class QualifiedNameFactory {
* @return A qualified name instance corresponding to the parsed string.
*/
public static JavaQualifiedName ofString(String name) {
return ofStringWithClassLoader(name, null);
}
private static JavaQualifiedName ofStringWithClassLoader(String name, ClassLoader classLoader) {
Matcher matcher = FORMAT.matcher(name);
if (!matcher.matches()) {
@ -153,8 +156,8 @@ public final class QualifiedNameFactory {
}
ImmutableList<String> packages = StringUtils.isBlank(matcher.group(PACKAGES_GROUP_INDEX))
? ListFactory.<String>emptyList()
: ListFactory.split(matcher.group(PACKAGES_GROUP_INDEX), "\\.");
? ListFactory.<String>emptyList()
: ListFactory.split(matcher.group(PACKAGES_GROUP_INDEX), "\\.");
String operation = matcher.group(OPERATION_GROUP_INDEX) == null ? null : matcher.group(OPERATION_GROUP_INDEX).substring(1);
boolean isLambda = operation != null && COMPILED_LAMBDA_PATTERN.matcher(operation).matches();
@ -175,7 +178,7 @@ public final class QualifiedNameFactory {
}
}
JavaTypeQualifiedName parent = new JavaTypeQualifiedName(packages, classes, localIndices);
JavaTypeQualifiedName parent = new JavaTypeQualifiedName(packages, classes, localIndices, classLoader);
return operation == null ? parent : new JavaOperationQualifiedName(parent, operation, isLambda);
}
}

View File

@ -9,6 +9,7 @@ import static net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName.NOTLOCAL
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.mutable.MutableInt;
@ -45,7 +46,7 @@ public class QualifiedNameResolver extends JavaParserVisitorReducedAdapter {
// Package names to package representation.
// Allows reusing the same list instance for the same packages.
// Package prefixes are also shared.
private final Map<String, ImmutableList<String>> foundPackages = new HashMap<>(128);
private static final Map<String, ImmutableList<String>> FOUND_PACKAGES = new ConcurrentHashMap<>(128);
// The following stacks stack some counter of the
// visited classes. A new entry is pushed when
@ -147,7 +148,7 @@ public class QualifiedNameResolver extends JavaParserVisitorReducedAdapter {
}
final String image = pack.getPackageNameImage();
ImmutableList<String> fullExisting = foundPackages.get(image);
ImmutableList<String> fullExisting = FOUND_PACKAGES.get(image);
if (fullExisting != null) {
return fullExisting;
@ -166,7 +167,7 @@ public class QualifiedNameResolver extends JavaParserVisitorReducedAdapter {
for (int i = longestPrefix.size(); i < allPacks.length; i++) {
longestPrefix = longestPrefix.prepend(allPacks[i]);
prefixImage.append(allPacks[i]);
foundPackages.put(prefixImage.toString(), longestPrefix);
FOUND_PACKAGES.put(prefixImage.toString(), longestPrefix);
}
return longestPrefix;
@ -184,7 +185,7 @@ public class QualifiedNameResolver extends JavaParserVisitorReducedAdapter {
* the total number of packages in the package name
*/
private ImmutableList<String> getLongestPackagePrefix(String acc, int i) {
ImmutableList<String> prefix = foundPackages.get(acc);
ImmutableList<String> prefix = FOUND_PACKAGES.get(acc);
if (prefix != null) {
return prefix;
}
@ -356,8 +357,7 @@ public class QualifiedNameResolver extends JavaParserVisitorReducedAdapter {
/** Creates a new class qname from the current context (fields). */
private JavaTypeQualifiedName contextClassQName() {
return new JavaTypeQualifiedName(packages, classNames, localIndices)
.withClassLoader(classLoader);
return new JavaTypeQualifiedName(packages, classNames, localIndices, classLoader);
}