Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refinements to AssociatedConverterImpl.cache #7976

Merged
merged 3 commits into from May 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 34 additions & 13 deletions core/src/main/java/hudson/util/XStream2.java
Expand Up @@ -469,8 +469,18 @@
*/
private static final class AssociatedConverterImpl implements Converter {
private final XStream xstream;
private final ConcurrentHashMap<Class<?>, Converter> cache =
new ConcurrentHashMap<>();
private static final ClassValue<Class<? extends ConverterMatcher>> classCache = new ClassValue<Class<? extends ConverterMatcher>>() {
@Override
protected Class<? extends ConverterMatcher> computeValue(Class<?> type) {
return computeConverterClass(type);
}
};
private final ClassValue<Converter> cache = new ClassValue<Converter>() {
@Override
protected Converter computeValue(Class<?> type) {
return computeConverter(type);
}
};

private AssociatedConverterImpl(XStream xstream) {
this.xstream = xstream;
Expand All @@ -481,17 +491,33 @@
if (t == null) {
return null;
}
return cache.get(t);
}

Converter result = cache.get(t);
if (result != null)
// ConcurrentHashMap does not allow null, so use this object to represent null
return result == this ? null : result;
@CheckForNull
private static Class<? extends ConverterMatcher> computeConverterClass(@NonNull Class<?> t) {
try {
final ClassLoader classLoader = t.getClassLoader();
if (classLoader == null) {
return null;
}
Class<?> cl = classLoader.loadClass(t.getName() + "$ConverterImpl");
String name = t.getName() + "$ConverterImpl";
if (classLoader.getResource(name.replace('.', '/') + ".class") == null) {
return null;
}
return classLoader.loadClass(name).asSubclass(ConverterMatcher.class);
} catch (ClassNotFoundException e) {

Check warning on line 509 in core/src/main/java/hudson/util/XStream2.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 509 is not covered by tests
return null;

Check warning on line 510 in core/src/main/java/hudson/util/XStream2.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 510 is not covered by tests
}
}

@CheckForNull
private Converter computeConverter(@NonNull Class<?> t) {
Class<? extends ConverterMatcher> cl = classCache.get(t);
if (cl == null) {
return null;
}
try {
Constructor<?> c = cl.getConstructors()[0];

Class<?>[] p = c.getParameterTypes();
Expand All @@ -506,14 +532,9 @@

}
ConverterMatcher cm = (ConverterMatcher) c.newInstance(args);
result = cm instanceof SingleValueConverter
return cm instanceof SingleValueConverter
? new SingleValueConverterWrapper((SingleValueConverter) cm)
: (Converter) cm;
cache.put(t, result);
return result;
} catch (ClassNotFoundException e) {
cache.put(t, this); // See above.. this object in cache represents null
return null;
} catch (IllegalAccessException e) {
IllegalAccessError x = new IllegalAccessError();
x.initCause(e);
Expand Down