Skip to content

Commit

Permalink
Merge pull request orphan-oss#77 from JCgH4164838Gh792C124B5/localOGN…
Browse files Browse the repository at this point in the history
…L_3_1_ClearCacheEnh

Cache clearing enhancement (clear additional cache, synchronization fix):

(cherry picked from commit 74f857c)
  • Loading branch information
lukaszlenart authored and JCgH4164838Gh792C124B5 committed Sep 29, 2019
1 parent 888b193 commit a1f33af
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 13 deletions.
3 changes: 3 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@
<archive>
<compress>true</compress>
<index>true</index>
<manifestEntries>
<Automatic-Module-Name>ognl</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
Expand Down
87 changes: 74 additions & 13 deletions src/main/java/ognl/OgnlRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -363,21 +363,65 @@ public class OgnlRuntime {
*/
public static void clearCache()
{
_methodParameterTypesCache.clear();
_ctorParameterTypesCache.clear();
_propertyDescriptorCache.clear();
_constructorCache.clear();
_staticMethodCache.clear();
_instanceMethodCache.clear();
_invokePermissionCache.clear();
_fieldCache.clear();
_superclasses.clear();
_declaredMethods[0].clear();
_declaredMethods[1].clear();
synchronized(_methodParameterTypesCache) {
_methodParameterTypesCache.clear();
}
synchronized(_ctorParameterTypesCache) {
_ctorParameterTypesCache.clear();
}
synchronized(_propertyDescriptorCache) {
_propertyDescriptorCache.clear();
}
synchronized(_constructorCache) {
_constructorCache.clear();
}
synchronized(_staticMethodCache) {
_staticMethodCache.clear();
}
synchronized(_instanceMethodCache) {
_instanceMethodCache.clear();
}
synchronized(_invokePermissionCache) {
_invokePermissionCache.clear();
}
synchronized(_fieldCache) {
_fieldCache.clear();
_superclasses.clear(); // Used by fieldCache lookup (synchronized on _fieldCache).
}
synchronized(_declaredMethods[0]) {
_declaredMethods[0].clear();
}
synchronized(_declaredMethods[1]) {
_declaredMethods[1].clear();
}
_methodAccessCache.clear();
_methodPermCache.clear();
}

/**
* Clears some additional caches used by OgnlRuntime. The existing {@link OgnlRuntime#clearCache()}
* clears the standard reflection-related caches, but some applications may have need to clear
* the additional caches as well.
*
* Clearing the additional caches may have greater impact than the {@link OgnlRuntime#clearCache()}
* method so it should only be used when the normal cache clear is insufficient.
*
* <p>
* <strong>Warning:</strong> Calling this method too often can be a huge performance
* drain on your expressions - use with care.
* </p>
*
* @since 3.1.25
*/
public static void clearAdditionalCache()
{
cacheSetMethod.clear();
cacheGetMethod.clear();
synchronized(_genericMethodParameterTypesCache) {
_genericMethodParameterTypesCache.clear();
}
}

/**
* Checks if the current jvm is java language >= 1.5 compatible.
*
Expand Down Expand Up @@ -1429,8 +1473,16 @@ private static MatchingMethod findBestMethod(List methods, Class typeClass, Stri
}
}
if (scoreCurr == scoreOther) {
if (failure == null)
System.err.println("Two methods with same score("+score+"): \""+mm.mMethod+"\" and \""+m+"\" please report!");
if (failure == null) {
boolean currentIsAbstract = Modifier.isAbstract(mm.mMethod.getModifiers());
boolean otherIsAbstract = Modifier.isAbstract(m.getModifiers());
if (! (currentIsAbstract ^ otherIsAbstract) ) {
// Only report as an error when the score is equal and BOTH methods are abstract or BOTH are concrete.
// If one is abstract and the other concrete then either choice should work for OGNL,
// so we just keep the current choice and continue (without error output).
System.err.println("Two methods with same score("+score+"): \""+mm.mMethod+"\" and \""+m+"\" please report!");
}
}
} else if (scoreCurr > scoreOther) {
// other wins...
mm = new MatchingMethod(m, score, report, mParameterTypes);
Expand Down Expand Up @@ -3359,6 +3411,15 @@ boolean containsKey(Class clazz, String propertyName)
return methodsByPropertyName.containsKey(propertyName);
}

/**
* Allow clearing for the underlying cache of the ClassPropertyMethodCache.
*
* @since 3.1.25
*/
void clear() {
this.cache.clear();
}

}


Expand Down
40 changes: 40 additions & 0 deletions src/test/java/ognl/TestOgnlRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ public void test_Class_Cache_Inspector()
throws Exception
{
OgnlRuntime.clearCache();
OgnlRuntime.clearAdditionalCache(); // Testing no exception only.
assertEquals(0, OgnlRuntime._propertyDescriptorCache.getSize());
assertEquals(0, OgnlRuntime._genericMethodParameterTypesCache.size());

Root root = new Root();
OgnlContext context = (OgnlContext) this.context;
Expand All @@ -196,7 +198,9 @@ public void test_Class_Cache_Inspector()
assertTrue(size > 0);

OgnlRuntime.clearCache();
OgnlRuntime.clearAdditionalCache(); // Testing no exception only.
assertEquals(0, OgnlRuntime._propertyDescriptorCache.getSize());
assertEquals(0, OgnlRuntime._genericMethodParameterTypesCache.size());

// now register class cache prevention

Expand Down Expand Up @@ -346,4 +350,40 @@ public void testGetStaticFieldEnumStatic() throws Exception {
Object obj = OgnlRuntime.getStaticField(context, "org.ognl.test.objects.OtherEnum", "STATIC_STRING");
assertEquals(OtherEnum.STATIC_STRING, obj);
}

/**
* This test indirectly confirms an error output (syserr) is no longer produced when OgnlRuntime
* encounters the condition reported in issue #17. {@link OgnlRuntime#findBestMethod} can find
* two appropriate methods with the same score where one is abstract and one is concrete. Either
* choice in that scenario actually worked when invoked, but produced the unwanted syserr output.
*
* @throws Exception
*/
public void testAbstractConcreteMethodScoringNoSysErr() throws Exception {
OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null);
ObjectMethodAccessor methodAccessor = new ObjectMethodAccessor();
ConcreteTestClass concreteTestClass = new ConcreteTestClass();
Object result = methodAccessor.callMethod(context, concreteTestClass, "testMethod", new Object[]{"Test", 1});
// The "Two methods with same score(0) ..." error output should no longer be seen with the above call.
assertEquals("Result not concatenation of parameters ?", "Test" + 1, result);
}

/**
* Abstract test class for issue #42 - equal score syserr output for abstract class/method hierarchy.
*
* @param <T>
*/
abstract class AbstractTestClass <T> {
public abstract String testMethod (T element, int i);
}

/**
* Concrete test class for issue #42 - equal score syserr output for abstract class/method hierarchy.
*/
class ConcreteTestClass extends AbstractTestClass < String > {
public String testMethod (String element, int i) {
return element + i;
}
}

}

0 comments on commit a1f33af

Please sign in to comment.